2013-11-12 11:46:16 -06:00
/*
2017-07-06 09:59:16 -05:00
* AMD Secure Processor device driver
2013-11-12 11:46:16 -06:00
*
2018-12-18 15:48:29 +00:00
* Copyright ( C ) 2013 , 2018 Advanced Micro Devices , Inc .
2013-11-12 11:46:16 -06:00
*
* Author : Tom Lendacky < thomas . lendacky @ amd . com >
2016-07-26 19:09:20 -05:00
* Author : Gary R Hook < gary . hook @ amd . com >
2013-11-12 11:46:16 -06:00
*
* 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 <linux/module.h>
# include <linux/kernel.h>
2014-06-05 10:17:45 -05:00
# include <linux/device.h>
2013-11-12 11:46:16 -06:00
# include <linux/pci.h>
# include <linux/pci_ids.h>
2014-06-05 10:17:45 -05:00
# include <linux/dma-mapping.h>
2013-11-12 11:46:16 -06:00
# include <linux/kthread.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include <linux/delay.h>
# include <linux/ccp.h>
# include "ccp-dev.h"
2017-12-04 10:57:28 -06:00
# include "psp-dev.h"
2013-11-12 11:46:16 -06:00
# define MSIX_VECTORS 2
2017-07-06 09:59:16 -05:00
struct sp_pci {
2013-11-12 11:46:16 -06:00
int msix_count ;
2017-07-06 09:59:15 -05:00
struct msix_entry msix_entry [ MSIX_VECTORS ] ;
2013-11-12 11:46:16 -06:00
} ;
2017-12-04 10:57:28 -06:00
static struct sp_device * sp_dev_master ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
static int sp_get_msix_irqs ( struct sp_device * sp )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:16 -05:00
struct sp_pci * sp_pci = sp - > dev_specific ;
2017-07-06 09:59:15 -05:00
struct device * dev = sp - > dev ;
2015-12-23 20:49:01 +08:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
2013-11-12 11:46:16 -06:00
int v , ret ;
2017-07-06 09:59:16 -05:00
for ( v = 0 ; v < ARRAY_SIZE ( sp_pci - > msix_entry ) ; v + + )
sp_pci - > msix_entry [ v ] . entry = v ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
ret = pci_enable_msix_range ( pdev , sp_pci - > msix_entry , 1 , v ) ;
2014-04-15 09:54:31 +02:00
if ( ret < 0 )
2013-11-12 11:46:16 -06:00
return ret ;
2017-07-06 09:59:16 -05:00
sp_pci - > msix_count = ret ;
2017-07-06 09:59:15 -05:00
sp - > use_tasklet = true ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
sp - > psp_irq = sp_pci - > msix_entry [ 0 ] . vector ;
sp - > ccp_irq = ( sp_pci - > msix_count > 1 ) ? sp_pci - > msix_entry [ 1 ] . vector
: sp_pci - > msix_entry [ 0 ] . vector ;
2013-11-12 11:46:16 -06:00
return 0 ;
}
2017-07-06 09:59:16 -05:00
static int sp_get_msi_irq ( struct sp_device * sp )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:15 -05:00
struct device * dev = sp - > dev ;
2015-12-23 20:49:01 +08:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
2013-11-12 11:46:16 -06:00
int ret ;
ret = pci_enable_msi ( pdev ) ;
if ( ret )
return ret ;
2017-07-06 09:59:15 -05:00
sp - > ccp_irq = pdev - > irq ;
sp - > psp_irq = pdev - > irq ;
2013-11-12 11:46:16 -06:00
return 0 ;
}
2017-07-06 09:59:16 -05:00
static int sp_get_irqs ( struct sp_device * sp )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:15 -05:00
struct device * dev = sp - > dev ;
2013-11-12 11:46:16 -06:00
int ret ;
2017-07-06 09:59:16 -05:00
ret = sp_get_msix_irqs ( sp ) ;
2013-11-12 11:46:16 -06:00
if ( ! ret )
return 0 ;
/* Couldn't get MSI-X vectors, try MSI */
dev_notice ( dev , " could not enable MSI-X (%d), trying MSI \n " , ret ) ;
2017-07-06 09:59:16 -05:00
ret = sp_get_msi_irq ( sp ) ;
2013-11-12 11:46:16 -06:00
if ( ! ret )
return 0 ;
/* Couldn't get MSI interrupt */
dev_notice ( dev , " could not enable MSI (%d) \n " , ret ) ;
return ret ;
}
2017-07-06 09:59:16 -05:00
static void sp_free_irqs ( struct sp_device * sp )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:16 -05:00
struct sp_pci * sp_pci = sp - > dev_specific ;
2017-07-06 09:59:15 -05:00
struct device * dev = sp - > dev ;
2015-12-23 20:49:01 +08:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
if ( sp_pci - > msix_count )
2013-11-12 11:46:16 -06:00
pci_disable_msix ( pdev ) ;
2017-07-06 09:59:15 -05:00
else if ( sp - > psp_irq )
2013-11-12 11:46:16 -06:00
pci_disable_msi ( pdev ) ;
2017-07-06 09:59:15 -05:00
sp - > ccp_irq = 0 ;
sp - > psp_irq = 0 ;
2013-11-12 11:46:16 -06:00
}
2017-12-04 10:57:28 -06:00
static bool sp_pci_is_master ( struct sp_device * sp )
{
struct device * dev_cur , * dev_new ;
struct pci_dev * pdev_cur , * pdev_new ;
dev_new = sp - > dev ;
dev_cur = sp_dev_master - > dev ;
pdev_new = to_pci_dev ( dev_new ) ;
pdev_cur = to_pci_dev ( dev_cur ) ;
if ( pdev_new - > bus - > number < pdev_cur - > bus - > number )
return true ;
if ( PCI_SLOT ( pdev_new - > devfn ) < PCI_SLOT ( pdev_cur - > devfn ) )
return true ;
if ( PCI_FUNC ( pdev_new - > devfn ) < PCI_FUNC ( pdev_cur - > devfn ) )
return true ;
return false ;
}
static void psp_set_master ( struct sp_device * sp )
{
if ( ! sp_dev_master ) {
sp_dev_master = sp ;
return ;
}
if ( sp_pci_is_master ( sp ) )
sp_dev_master = sp ;
}
static struct sp_device * psp_get_master ( void )
{
return sp_dev_master ;
}
2017-07-06 09:59:16 -05:00
static int sp_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:14 -05:00
struct sp_device * sp ;
2017-07-06 09:59:16 -05:00
struct sp_pci * sp_pci ;
2013-11-12 11:46:16 -06:00
struct device * dev = & pdev - > dev ;
2017-07-06 09:59:13 -05:00
void __iomem * const * iomap_table ;
int bar_mask ;
2013-11-12 11:46:16 -06:00
int ret ;
ret = - ENOMEM ;
2017-07-06 09:59:14 -05:00
sp = sp_alloc_struct ( dev ) ;
if ( ! sp )
2013-11-12 11:46:16 -06:00
goto e_err ;
2017-07-06 09:59:16 -05:00
sp_pci = devm_kzalloc ( dev , sizeof ( * sp_pci ) , GFP_KERNEL ) ;
if ( ! sp_pci )
2015-02-03 13:07:23 -06:00
goto e_err ;
2017-07-06 09:59:16 -05:00
sp - > dev_specific = sp_pci ;
2017-07-06 09:59:14 -05:00
sp - > dev_vdata = ( struct sp_dev_vdata * ) id - > driver_data ;
if ( ! sp - > dev_vdata ) {
2016-03-01 13:49:15 -06:00
ret = - ENODEV ;
dev_err ( dev , " missing driver data \n " ) ;
goto e_err ;
}
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:13 -05:00
ret = pcim_enable_device ( pdev ) ;
2013-11-12 11:46:16 -06:00
if ( ret ) {
2017-07-06 09:59:13 -05:00
dev_err ( dev , " pcim_enable_device failed (%d) \n " , ret ) ;
2015-02-03 13:07:23 -06:00
goto e_err ;
2013-11-12 11:46:16 -06:00
}
2017-07-06 09:59:13 -05:00
bar_mask = pci_select_bars ( pdev , IORESOURCE_MEM ) ;
ret = pcim_iomap_regions ( pdev , bar_mask , " ccp " ) ;
2013-11-12 11:46:16 -06:00
if ( ret ) {
2017-07-06 09:59:13 -05:00
dev_err ( dev , " pcim_iomap_regions failed (%d) \n " , ret ) ;
goto e_err ;
2013-11-12 11:46:16 -06:00
}
2017-07-06 09:59:13 -05:00
iomap_table = pcim_iomap_table ( pdev ) ;
if ( ! iomap_table ) {
dev_err ( dev , " pcim_iomap_table failed \n " ) ;
ret = - ENOMEM ;
goto e_err ;
}
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:14 -05:00
sp - > io_map = iomap_table [ sp - > dev_vdata - > bar ] ;
if ( ! sp - > io_map ) {
2017-07-06 09:59:13 -05:00
dev_err ( dev , " ioremap failed \n " ) ;
ret = - ENOMEM ;
goto e_err ;
2013-11-12 11:46:16 -06:00
}
2017-07-06 09:59:13 -05:00
2017-07-06 09:59:16 -05:00
ret = sp_get_irqs ( sp ) ;
2017-07-06 09:59:15 -05:00
if ( ret )
goto e_err ;
2017-07-06 09:59:13 -05:00
pci_set_master ( pdev ) ;
2017-12-04 10:57:28 -06:00
sp - > set_psp_master_device = psp_set_master ;
sp - > get_psp_master_device = psp_get_master ;
2013-11-12 11:46:16 -06:00
2014-06-05 10:17:45 -05:00
ret = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 48 ) ) ;
if ( ret ) {
ret = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
2013-11-12 11:46:16 -06:00
if ( ret ) {
2014-06-05 10:17:45 -05:00
dev_err ( dev , " dma_set_mask_and_coherent failed (%d) \n " ,
2013-11-12 11:46:16 -06:00
ret ) ;
2017-07-06 09:59:13 -05:00
goto e_err ;
2013-11-12 11:46:16 -06:00
}
}
2017-07-06 09:59:14 -05:00
dev_set_drvdata ( dev , sp ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:14 -05:00
ret = sp_init ( sp ) ;
2013-11-12 11:46:16 -06:00
if ( ret )
2017-07-06 09:59:13 -05:00
goto e_err ;
2013-11-12 11:46:16 -06:00
return 0 ;
e_err :
dev_notice ( dev , " initialization failed \n " ) ;
return ret ;
}
2017-07-06 09:59:16 -05:00
static void sp_pci_remove ( struct pci_dev * pdev )
2013-11-12 11:46:16 -06:00
{
struct device * dev = & pdev - > dev ;
2017-07-06 09:59:14 -05:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:14 -05:00
if ( ! sp )
2014-01-06 13:34:29 -06:00
return ;
2017-07-06 09:59:14 -05:00
sp_destroy ( sp ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
sp_free_irqs ( sp ) ;
2013-11-12 11:46:16 -06:00
}
# ifdef CONFIG_PM
2017-07-06 09:59:16 -05:00
static int sp_pci_suspend ( struct pci_dev * pdev , pm_message_t state )
2013-11-12 11:46:16 -06:00
{
struct device * dev = & pdev - > dev ;
2017-07-06 09:59:14 -05:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:14 -05:00
return sp_suspend ( sp , state ) ;
2013-11-12 11:46:16 -06:00
}
2017-07-06 09:59:16 -05:00
static int sp_pci_resume ( struct pci_dev * pdev )
2013-11-12 11:46:16 -06:00
{
struct device * dev = & pdev - > dev ;
2017-07-06 09:59:14 -05:00
struct sp_device * sp = dev_get_drvdata ( dev ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:14 -05:00
return sp_resume ( sp ) ;
2013-11-12 11:46:16 -06:00
}
# endif
2017-12-04 10:57:28 -06:00
# ifdef CONFIG_CRYPTO_DEV_SP_PSP
2018-07-03 12:12:14 -05:00
static const struct psp_vdata pspv1 = {
2018-07-03 12:12:03 -05:00
. cmdresp_reg = 0x10580 ,
. cmdbuff_addr_lo_reg = 0x105e0 ,
. cmdbuff_addr_hi_reg = 0x105e4 ,
. feature_reg = 0x105fc ,
. inten_reg = 0x10610 ,
. intsts_reg = 0x10614 ,
2017-12-04 10:57:28 -06:00
} ;
2018-07-03 12:12:14 -05:00
static const struct psp_vdata pspv2 = {
. cmdresp_reg = 0x10980 ,
. cmdbuff_addr_lo_reg = 0x109e0 ,
. cmdbuff_addr_hi_reg = 0x109e4 ,
. feature_reg = 0x109fc ,
. inten_reg = 0x10690 ,
. intsts_reg = 0x10694 ,
} ;
2017-12-04 10:57:28 -06:00
# endif
2017-07-06 09:59:14 -05:00
static const struct sp_dev_vdata dev_vdata [ ] = {
2018-07-03 12:12:14 -05:00
{ /* 0 */
2017-07-06 09:59:14 -05:00
. bar = 2 ,
# ifdef CONFIG_CRYPTO_DEV_SP_CCP
. ccp_vdata = & ccpv3 ,
# endif
} ,
2018-07-03 12:12:14 -05:00
{ /* 1 */
2017-07-06 09:59:14 -05:00
. bar = 2 ,
# ifdef CONFIG_CRYPTO_DEV_SP_CCP
. ccp_vdata = & ccpv5a ,
2017-12-04 10:57:28 -06:00
# endif
# ifdef CONFIG_CRYPTO_DEV_SP_PSP
2018-07-03 12:12:14 -05:00
. psp_vdata = & pspv1 ,
2017-07-06 09:59:14 -05:00
# endif
} ,
2018-07-03 12:12:14 -05:00
{ /* 2 */
2017-07-06 09:59:14 -05:00
. bar = 2 ,
# ifdef CONFIG_CRYPTO_DEV_SP_CCP
. ccp_vdata = & ccpv5b ,
2018-07-03 12:12:14 -05:00
# endif
} ,
{ /* 3 */
. bar = 2 ,
# ifdef CONFIG_CRYPTO_DEV_SP_CCP
. ccp_vdata = & ccpv5a ,
# endif
# ifdef CONFIG_CRYPTO_DEV_SP_PSP
. psp_vdata = & pspv2 ,
2017-07-06 09:59:14 -05:00
# endif
} ,
} ;
2017-07-06 09:59:16 -05:00
static const struct pci_device_id sp_pci_table [ ] = {
2017-07-06 09:59:14 -05:00
{ PCI_VDEVICE ( AMD , 0x1537 ) , ( kernel_ulong_t ) & dev_vdata [ 0 ] } ,
{ PCI_VDEVICE ( AMD , 0x1456 ) , ( kernel_ulong_t ) & dev_vdata [ 1 ] } ,
{ PCI_VDEVICE ( AMD , 0x1468 ) , ( kernel_ulong_t ) & dev_vdata [ 2 ] } ,
2018-07-03 12:12:14 -05:00
{ PCI_VDEVICE ( AMD , 0x1486 ) , ( kernel_ulong_t ) & dev_vdata [ 3 ] } ,
2013-11-12 11:46:16 -06:00
/* Last entry must be zero */
{ 0 , }
} ;
2017-07-06 09:59:16 -05:00
MODULE_DEVICE_TABLE ( pci , sp_pci_table ) ;
2013-11-12 11:46:16 -06:00
2017-07-06 09:59:16 -05:00
static struct pci_driver sp_pci_driver = {
2015-10-01 16:32:50 -05:00
. name = " ccp " ,
2017-07-06 09:59:16 -05:00
. id_table = sp_pci_table ,
. probe = sp_pci_probe ,
. remove = sp_pci_remove ,
2013-11-12 11:46:16 -06:00
# ifdef CONFIG_PM
2017-07-06 09:59:16 -05:00
. suspend = sp_pci_suspend ,
. resume = sp_pci_resume ,
2013-11-12 11:46:16 -06:00
# endif
} ;
2017-07-06 09:59:16 -05:00
int sp_pci_init ( void )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:16 -05:00
return pci_register_driver ( & sp_pci_driver ) ;
2013-11-12 11:46:16 -06:00
}
2017-07-06 09:59:16 -05:00
void sp_pci_exit ( void )
2013-11-12 11:46:16 -06:00
{
2017-07-06 09:59:16 -05:00
pci_unregister_driver ( & sp_pci_driver ) ;
2013-11-12 11:46:16 -06:00
}