1*d0ebbc0cSBrijesh Singh /* 2*d0ebbc0cSBrijesh Singh * AMD Secure Processor device driver 3*d0ebbc0cSBrijesh Singh * 4*d0ebbc0cSBrijesh Singh * Copyright (C) 2013,2016 Advanced Micro Devices, Inc. 5*d0ebbc0cSBrijesh Singh * 6*d0ebbc0cSBrijesh Singh * Author: Tom Lendacky <thomas.lendacky@amd.com> 7*d0ebbc0cSBrijesh Singh * Author: Gary R Hook <gary.hook@amd.com> 8*d0ebbc0cSBrijesh Singh * 9*d0ebbc0cSBrijesh Singh * This program is free software; you can redistribute it and/or modify 10*d0ebbc0cSBrijesh Singh * it under the terms of the GNU General Public License version 2 as 11*d0ebbc0cSBrijesh Singh * published by the Free Software Foundation. 12*d0ebbc0cSBrijesh Singh */ 13*d0ebbc0cSBrijesh Singh 14*d0ebbc0cSBrijesh Singh #include <linux/module.h> 15*d0ebbc0cSBrijesh Singh #include <linux/kernel.h> 16*d0ebbc0cSBrijesh Singh #include <linux/device.h> 17*d0ebbc0cSBrijesh Singh #include <linux/pci.h> 18*d0ebbc0cSBrijesh Singh #include <linux/pci_ids.h> 19*d0ebbc0cSBrijesh Singh #include <linux/dma-mapping.h> 20*d0ebbc0cSBrijesh Singh #include <linux/kthread.h> 21*d0ebbc0cSBrijesh Singh #include <linux/sched.h> 22*d0ebbc0cSBrijesh Singh #include <linux/interrupt.h> 23*d0ebbc0cSBrijesh Singh #include <linux/spinlock.h> 24*d0ebbc0cSBrijesh Singh #include <linux/delay.h> 25*d0ebbc0cSBrijesh Singh #include <linux/ccp.h> 26*d0ebbc0cSBrijesh Singh 27*d0ebbc0cSBrijesh Singh #include "ccp-dev.h" 28*d0ebbc0cSBrijesh Singh 29*d0ebbc0cSBrijesh Singh #define MSIX_VECTORS 2 30*d0ebbc0cSBrijesh Singh 31*d0ebbc0cSBrijesh Singh struct sp_pci { 32*d0ebbc0cSBrijesh Singh int msix_count; 33*d0ebbc0cSBrijesh Singh struct msix_entry msix_entry[MSIX_VECTORS]; 34*d0ebbc0cSBrijesh Singh }; 35*d0ebbc0cSBrijesh Singh 36*d0ebbc0cSBrijesh Singh static int sp_get_msix_irqs(struct sp_device *sp) 37*d0ebbc0cSBrijesh Singh { 38*d0ebbc0cSBrijesh Singh struct sp_pci *sp_pci = sp->dev_specific; 39*d0ebbc0cSBrijesh Singh struct device *dev = sp->dev; 40*d0ebbc0cSBrijesh Singh struct pci_dev *pdev = to_pci_dev(dev); 41*d0ebbc0cSBrijesh Singh int v, ret; 42*d0ebbc0cSBrijesh Singh 43*d0ebbc0cSBrijesh Singh for (v = 0; v < ARRAY_SIZE(sp_pci->msix_entry); v++) 44*d0ebbc0cSBrijesh Singh sp_pci->msix_entry[v].entry = v; 45*d0ebbc0cSBrijesh Singh 46*d0ebbc0cSBrijesh Singh ret = pci_enable_msix_range(pdev, sp_pci->msix_entry, 1, v); 47*d0ebbc0cSBrijesh Singh if (ret < 0) 48*d0ebbc0cSBrijesh Singh return ret; 49*d0ebbc0cSBrijesh Singh 50*d0ebbc0cSBrijesh Singh sp_pci->msix_count = ret; 51*d0ebbc0cSBrijesh Singh sp->use_tasklet = true; 52*d0ebbc0cSBrijesh Singh 53*d0ebbc0cSBrijesh Singh sp->psp_irq = sp_pci->msix_entry[0].vector; 54*d0ebbc0cSBrijesh Singh sp->ccp_irq = (sp_pci->msix_count > 1) ? sp_pci->msix_entry[1].vector 55*d0ebbc0cSBrijesh Singh : sp_pci->msix_entry[0].vector; 56*d0ebbc0cSBrijesh Singh return 0; 57*d0ebbc0cSBrijesh Singh } 58*d0ebbc0cSBrijesh Singh 59*d0ebbc0cSBrijesh Singh static int sp_get_msi_irq(struct sp_device *sp) 60*d0ebbc0cSBrijesh Singh { 61*d0ebbc0cSBrijesh Singh struct device *dev = sp->dev; 62*d0ebbc0cSBrijesh Singh struct pci_dev *pdev = to_pci_dev(dev); 63*d0ebbc0cSBrijesh Singh int ret; 64*d0ebbc0cSBrijesh Singh 65*d0ebbc0cSBrijesh Singh ret = pci_enable_msi(pdev); 66*d0ebbc0cSBrijesh Singh if (ret) 67*d0ebbc0cSBrijesh Singh return ret; 68*d0ebbc0cSBrijesh Singh 69*d0ebbc0cSBrijesh Singh sp->ccp_irq = pdev->irq; 70*d0ebbc0cSBrijesh Singh sp->psp_irq = pdev->irq; 71*d0ebbc0cSBrijesh Singh 72*d0ebbc0cSBrijesh Singh return 0; 73*d0ebbc0cSBrijesh Singh } 74*d0ebbc0cSBrijesh Singh 75*d0ebbc0cSBrijesh Singh static int sp_get_irqs(struct sp_device *sp) 76*d0ebbc0cSBrijesh Singh { 77*d0ebbc0cSBrijesh Singh struct device *dev = sp->dev; 78*d0ebbc0cSBrijesh Singh int ret; 79*d0ebbc0cSBrijesh Singh 80*d0ebbc0cSBrijesh Singh ret = sp_get_msix_irqs(sp); 81*d0ebbc0cSBrijesh Singh if (!ret) 82*d0ebbc0cSBrijesh Singh return 0; 83*d0ebbc0cSBrijesh Singh 84*d0ebbc0cSBrijesh Singh /* Couldn't get MSI-X vectors, try MSI */ 85*d0ebbc0cSBrijesh Singh dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret); 86*d0ebbc0cSBrijesh Singh ret = sp_get_msi_irq(sp); 87*d0ebbc0cSBrijesh Singh if (!ret) 88*d0ebbc0cSBrijesh Singh return 0; 89*d0ebbc0cSBrijesh Singh 90*d0ebbc0cSBrijesh Singh /* Couldn't get MSI interrupt */ 91*d0ebbc0cSBrijesh Singh dev_notice(dev, "could not enable MSI (%d)\n", ret); 92*d0ebbc0cSBrijesh Singh 93*d0ebbc0cSBrijesh Singh return ret; 94*d0ebbc0cSBrijesh Singh } 95*d0ebbc0cSBrijesh Singh 96*d0ebbc0cSBrijesh Singh static void sp_free_irqs(struct sp_device *sp) 97*d0ebbc0cSBrijesh Singh { 98*d0ebbc0cSBrijesh Singh struct sp_pci *sp_pci = sp->dev_specific; 99*d0ebbc0cSBrijesh Singh struct device *dev = sp->dev; 100*d0ebbc0cSBrijesh Singh struct pci_dev *pdev = to_pci_dev(dev); 101*d0ebbc0cSBrijesh Singh 102*d0ebbc0cSBrijesh Singh if (sp_pci->msix_count) 103*d0ebbc0cSBrijesh Singh pci_disable_msix(pdev); 104*d0ebbc0cSBrijesh Singh else if (sp->psp_irq) 105*d0ebbc0cSBrijesh Singh pci_disable_msi(pdev); 106*d0ebbc0cSBrijesh Singh 107*d0ebbc0cSBrijesh Singh sp->ccp_irq = 0; 108*d0ebbc0cSBrijesh Singh sp->psp_irq = 0; 109*d0ebbc0cSBrijesh Singh } 110*d0ebbc0cSBrijesh Singh 111*d0ebbc0cSBrijesh Singh static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 112*d0ebbc0cSBrijesh Singh { 113*d0ebbc0cSBrijesh Singh struct sp_device *sp; 114*d0ebbc0cSBrijesh Singh struct sp_pci *sp_pci; 115*d0ebbc0cSBrijesh Singh struct device *dev = &pdev->dev; 116*d0ebbc0cSBrijesh Singh void __iomem * const *iomap_table; 117*d0ebbc0cSBrijesh Singh int bar_mask; 118*d0ebbc0cSBrijesh Singh int ret; 119*d0ebbc0cSBrijesh Singh 120*d0ebbc0cSBrijesh Singh ret = -ENOMEM; 121*d0ebbc0cSBrijesh Singh sp = sp_alloc_struct(dev); 122*d0ebbc0cSBrijesh Singh if (!sp) 123*d0ebbc0cSBrijesh Singh goto e_err; 124*d0ebbc0cSBrijesh Singh 125*d0ebbc0cSBrijesh Singh sp_pci = devm_kzalloc(dev, sizeof(*sp_pci), GFP_KERNEL); 126*d0ebbc0cSBrijesh Singh if (!sp_pci) 127*d0ebbc0cSBrijesh Singh goto e_err; 128*d0ebbc0cSBrijesh Singh 129*d0ebbc0cSBrijesh Singh sp->dev_specific = sp_pci; 130*d0ebbc0cSBrijesh Singh sp->dev_vdata = (struct sp_dev_vdata *)id->driver_data; 131*d0ebbc0cSBrijesh Singh if (!sp->dev_vdata) { 132*d0ebbc0cSBrijesh Singh ret = -ENODEV; 133*d0ebbc0cSBrijesh Singh dev_err(dev, "missing driver data\n"); 134*d0ebbc0cSBrijesh Singh goto e_err; 135*d0ebbc0cSBrijesh Singh } 136*d0ebbc0cSBrijesh Singh 137*d0ebbc0cSBrijesh Singh ret = pcim_enable_device(pdev); 138*d0ebbc0cSBrijesh Singh if (ret) { 139*d0ebbc0cSBrijesh Singh dev_err(dev, "pcim_enable_device failed (%d)\n", ret); 140*d0ebbc0cSBrijesh Singh goto e_err; 141*d0ebbc0cSBrijesh Singh } 142*d0ebbc0cSBrijesh Singh 143*d0ebbc0cSBrijesh Singh bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); 144*d0ebbc0cSBrijesh Singh ret = pcim_iomap_regions(pdev, bar_mask, "ccp"); 145*d0ebbc0cSBrijesh Singh if (ret) { 146*d0ebbc0cSBrijesh Singh dev_err(dev, "pcim_iomap_regions failed (%d)\n", ret); 147*d0ebbc0cSBrijesh Singh goto e_err; 148*d0ebbc0cSBrijesh Singh } 149*d0ebbc0cSBrijesh Singh 150*d0ebbc0cSBrijesh Singh iomap_table = pcim_iomap_table(pdev); 151*d0ebbc0cSBrijesh Singh if (!iomap_table) { 152*d0ebbc0cSBrijesh Singh dev_err(dev, "pcim_iomap_table failed\n"); 153*d0ebbc0cSBrijesh Singh ret = -ENOMEM; 154*d0ebbc0cSBrijesh Singh goto e_err; 155*d0ebbc0cSBrijesh Singh } 156*d0ebbc0cSBrijesh Singh 157*d0ebbc0cSBrijesh Singh sp->io_map = iomap_table[sp->dev_vdata->bar]; 158*d0ebbc0cSBrijesh Singh if (!sp->io_map) { 159*d0ebbc0cSBrijesh Singh dev_err(dev, "ioremap failed\n"); 160*d0ebbc0cSBrijesh Singh ret = -ENOMEM; 161*d0ebbc0cSBrijesh Singh goto e_err; 162*d0ebbc0cSBrijesh Singh } 163*d0ebbc0cSBrijesh Singh 164*d0ebbc0cSBrijesh Singh ret = sp_get_irqs(sp); 165*d0ebbc0cSBrijesh Singh if (ret) 166*d0ebbc0cSBrijesh Singh goto e_err; 167*d0ebbc0cSBrijesh Singh 168*d0ebbc0cSBrijesh Singh pci_set_master(pdev); 169*d0ebbc0cSBrijesh Singh 170*d0ebbc0cSBrijesh Singh ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 171*d0ebbc0cSBrijesh Singh if (ret) { 172*d0ebbc0cSBrijesh Singh ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 173*d0ebbc0cSBrijesh Singh if (ret) { 174*d0ebbc0cSBrijesh Singh dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", 175*d0ebbc0cSBrijesh Singh ret); 176*d0ebbc0cSBrijesh Singh goto e_err; 177*d0ebbc0cSBrijesh Singh } 178*d0ebbc0cSBrijesh Singh } 179*d0ebbc0cSBrijesh Singh 180*d0ebbc0cSBrijesh Singh dev_set_drvdata(dev, sp); 181*d0ebbc0cSBrijesh Singh 182*d0ebbc0cSBrijesh Singh ret = sp_init(sp); 183*d0ebbc0cSBrijesh Singh if (ret) 184*d0ebbc0cSBrijesh Singh goto e_err; 185*d0ebbc0cSBrijesh Singh 186*d0ebbc0cSBrijesh Singh dev_notice(dev, "enabled\n"); 187*d0ebbc0cSBrijesh Singh 188*d0ebbc0cSBrijesh Singh return 0; 189*d0ebbc0cSBrijesh Singh 190*d0ebbc0cSBrijesh Singh e_err: 191*d0ebbc0cSBrijesh Singh dev_notice(dev, "initialization failed\n"); 192*d0ebbc0cSBrijesh Singh return ret; 193*d0ebbc0cSBrijesh Singh } 194*d0ebbc0cSBrijesh Singh 195*d0ebbc0cSBrijesh Singh static void sp_pci_remove(struct pci_dev *pdev) 196*d0ebbc0cSBrijesh Singh { 197*d0ebbc0cSBrijesh Singh struct device *dev = &pdev->dev; 198*d0ebbc0cSBrijesh Singh struct sp_device *sp = dev_get_drvdata(dev); 199*d0ebbc0cSBrijesh Singh 200*d0ebbc0cSBrijesh Singh if (!sp) 201*d0ebbc0cSBrijesh Singh return; 202*d0ebbc0cSBrijesh Singh 203*d0ebbc0cSBrijesh Singh sp_destroy(sp); 204*d0ebbc0cSBrijesh Singh 205*d0ebbc0cSBrijesh Singh sp_free_irqs(sp); 206*d0ebbc0cSBrijesh Singh 207*d0ebbc0cSBrijesh Singh dev_notice(dev, "disabled\n"); 208*d0ebbc0cSBrijesh Singh } 209*d0ebbc0cSBrijesh Singh 210*d0ebbc0cSBrijesh Singh #ifdef CONFIG_PM 211*d0ebbc0cSBrijesh Singh static int sp_pci_suspend(struct pci_dev *pdev, pm_message_t state) 212*d0ebbc0cSBrijesh Singh { 213*d0ebbc0cSBrijesh Singh struct device *dev = &pdev->dev; 214*d0ebbc0cSBrijesh Singh struct sp_device *sp = dev_get_drvdata(dev); 215*d0ebbc0cSBrijesh Singh 216*d0ebbc0cSBrijesh Singh return sp_suspend(sp, state); 217*d0ebbc0cSBrijesh Singh } 218*d0ebbc0cSBrijesh Singh 219*d0ebbc0cSBrijesh Singh static int sp_pci_resume(struct pci_dev *pdev) 220*d0ebbc0cSBrijesh Singh { 221*d0ebbc0cSBrijesh Singh struct device *dev = &pdev->dev; 222*d0ebbc0cSBrijesh Singh struct sp_device *sp = dev_get_drvdata(dev); 223*d0ebbc0cSBrijesh Singh 224*d0ebbc0cSBrijesh Singh return sp_resume(sp); 225*d0ebbc0cSBrijesh Singh } 226*d0ebbc0cSBrijesh Singh #endif 227*d0ebbc0cSBrijesh Singh 228*d0ebbc0cSBrijesh Singh static const struct sp_dev_vdata dev_vdata[] = { 229*d0ebbc0cSBrijesh Singh { 230*d0ebbc0cSBrijesh Singh .bar = 2, 231*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP 232*d0ebbc0cSBrijesh Singh .ccp_vdata = &ccpv3, 233*d0ebbc0cSBrijesh Singh #endif 234*d0ebbc0cSBrijesh Singh }, 235*d0ebbc0cSBrijesh Singh { 236*d0ebbc0cSBrijesh Singh .bar = 2, 237*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP 238*d0ebbc0cSBrijesh Singh .ccp_vdata = &ccpv5a, 239*d0ebbc0cSBrijesh Singh #endif 240*d0ebbc0cSBrijesh Singh }, 241*d0ebbc0cSBrijesh Singh { 242*d0ebbc0cSBrijesh Singh .bar = 2, 243*d0ebbc0cSBrijesh Singh #ifdef CONFIG_CRYPTO_DEV_SP_CCP 244*d0ebbc0cSBrijesh Singh .ccp_vdata = &ccpv5b, 245*d0ebbc0cSBrijesh Singh #endif 246*d0ebbc0cSBrijesh Singh }, 247*d0ebbc0cSBrijesh Singh }; 248*d0ebbc0cSBrijesh Singh static const struct pci_device_id sp_pci_table[] = { 249*d0ebbc0cSBrijesh Singh { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] }, 250*d0ebbc0cSBrijesh Singh { PCI_VDEVICE(AMD, 0x1456), (kernel_ulong_t)&dev_vdata[1] }, 251*d0ebbc0cSBrijesh Singh { PCI_VDEVICE(AMD, 0x1468), (kernel_ulong_t)&dev_vdata[2] }, 252*d0ebbc0cSBrijesh Singh /* Last entry must be zero */ 253*d0ebbc0cSBrijesh Singh { 0, } 254*d0ebbc0cSBrijesh Singh }; 255*d0ebbc0cSBrijesh Singh MODULE_DEVICE_TABLE(pci, sp_pci_table); 256*d0ebbc0cSBrijesh Singh 257*d0ebbc0cSBrijesh Singh static struct pci_driver sp_pci_driver = { 258*d0ebbc0cSBrijesh Singh .name = "ccp", 259*d0ebbc0cSBrijesh Singh .id_table = sp_pci_table, 260*d0ebbc0cSBrijesh Singh .probe = sp_pci_probe, 261*d0ebbc0cSBrijesh Singh .remove = sp_pci_remove, 262*d0ebbc0cSBrijesh Singh #ifdef CONFIG_PM 263*d0ebbc0cSBrijesh Singh .suspend = sp_pci_suspend, 264*d0ebbc0cSBrijesh Singh .resume = sp_pci_resume, 265*d0ebbc0cSBrijesh Singh #endif 266*d0ebbc0cSBrijesh Singh }; 267*d0ebbc0cSBrijesh Singh 268*d0ebbc0cSBrijesh Singh int sp_pci_init(void) 269*d0ebbc0cSBrijesh Singh { 270*d0ebbc0cSBrijesh Singh return pci_register_driver(&sp_pci_driver); 271*d0ebbc0cSBrijesh Singh } 272*d0ebbc0cSBrijesh Singh 273*d0ebbc0cSBrijesh Singh void sp_pci_exit(void) 274*d0ebbc0cSBrijesh Singh { 275*d0ebbc0cSBrijesh Singh pci_unregister_driver(&sp_pci_driver); 276*d0ebbc0cSBrijesh Singh } 277