2018-01-26 20:45:16 +03:00
// SPDX-License-Identifier: GPL-2.0
2011-09-27 17:57:13 +04:00
/*
2018-03-10 01:36:33 +03:00
* PCI Express I / O Virtualization ( IOV ) support
2011-09-27 17:57:13 +04:00
* Address Translation Service 1.0
2011-09-27 17:57:15 +04:00
* Page Request Interface added by Joerg Roedel < joerg . roedel @ amd . com >
2011-09-27 17:57:16 +04:00
* PASID support added by Joerg Roedel < joerg . roedel @ amd . com >
2018-03-10 01:36:33 +03:00
*
* Copyright ( C ) 2009 Intel Corporation , Yu Zhao < yu . zhao @ intel . com >
* Copyright ( C ) 2011 Advanced Micro Devices ,
2011-09-27 17:57:13 +04:00
*/
2023-10-10 23:44:31 +03:00
# include <linux/bitfield.h>
2011-05-27 17:37:25 +04:00
# include <linux/export.h>
2011-09-27 17:57:13 +04:00
# include <linux/pci-ats.h>
# include <linux/pci.h>
2011-11-29 23:20:23 +04:00
# include <linux/slab.h>
2011-09-27 17:57:13 +04:00
# include "pci.h"
2015-07-17 23:35:18 +03:00
void pci_ats_init ( struct pci_dev * dev )
2011-09-27 17:57:13 +04:00
{
int pos ;
2018-05-11 01:56:02 +03:00
if ( pci_ats_disabled ( ) )
return ;
2011-09-27 17:57:13 +04:00
pos = pci_find_ext_capability ( dev , PCI_EXT_CAP_ID_ATS ) ;
if ( ! pos )
2015-07-17 23:05:46 +03:00
return ;
2011-09-27 17:57:13 +04:00
2015-07-17 23:15:19 +03:00
dev - > ats_cap = pos ;
2011-09-27 17:57:13 +04:00
}
2020-05-20 18:22:00 +03:00
/**
* pci_ats_supported - check if the device can use ATS
* @ dev : the PCI device
*
* Returns true if the device supports ATS and is allowed to use it , false
* otherwise .
*/
bool pci_ats_supported ( struct pci_dev * dev )
{
if ( ! dev - > ats_cap )
return false ;
return ( dev - > untrusted = = 0 ) ;
}
EXPORT_SYMBOL_GPL ( pci_ats_supported ) ;
2011-09-27 17:57:13 +04:00
/**
* pci_enable_ats - enable the ATS capability
* @ dev : the PCI device
* @ ps : the IOMMU page shift
*
* Returns 0 on success , or negative on failure .
*/
int pci_enable_ats ( struct pci_dev * dev , int ps )
{
u16 ctrl ;
2015-07-17 23:38:13 +03:00
struct pci_dev * pdev ;
2011-09-27 17:57:13 +04:00
2020-05-20 18:22:00 +03:00
if ( ! pci_ats_supported ( dev ) )
2015-07-17 23:05:46 +03:00
return - EINVAL ;
2015-07-20 17:23:37 +03:00
if ( WARN_ON ( dev - > ats_enabled ) )
2015-07-17 23:43:27 +03:00
return - EBUSY ;
2011-09-27 17:57:13 +04:00
if ( ps < PCI_ATS_MIN_STU )
return - EINVAL ;
2015-07-17 23:05:46 +03:00
/*
* Note that enabling ATS on a VF fails unless it ' s already enabled
* with the same STU on the PF .
*/
ctrl = PCI_ATS_CTRL_ENABLE ;
if ( dev - > is_virtfn ) {
2015-07-17 23:38:13 +03:00
pdev = pci_physfn ( dev ) ;
2015-07-17 23:15:19 +03:00
if ( pdev - > ats_stu ! = ps )
2015-07-17 23:05:46 +03:00
return - EINVAL ;
} else {
2015-07-17 23:15:19 +03:00
dev - > ats_stu = ps ;
ctrl | = PCI_ATS_CTRL_STU ( dev - > ats_stu - PCI_ATS_MIN_STU ) ;
2011-09-27 17:57:13 +04:00
}
2015-07-17 23:15:19 +03:00
pci_write_config_word ( dev , dev - > ats_cap + PCI_ATS_CTRL , ctrl ) ;
2011-09-27 17:57:13 +04:00
2015-07-17 23:15:19 +03:00
dev - > ats_enabled = 1 ;
2011-09-27 17:57:13 +04:00
return 0 ;
}
2019-12-19 15:03:39 +03:00
EXPORT_SYMBOL_GPL ( pci_enable_ats ) ;
2011-09-27 17:57:13 +04:00
/**
* pci_disable_ats - disable the ATS capability
* @ dev : the PCI device
*/
void pci_disable_ats ( struct pci_dev * dev )
{
u16 ctrl ;
2015-07-20 17:23:37 +03:00
if ( WARN_ON ( ! dev - > ats_enabled ) )
2015-07-17 23:43:27 +03:00
return ;
2011-09-27 17:57:13 +04:00
2015-07-17 23:15:19 +03:00
pci_read_config_word ( dev , dev - > ats_cap + PCI_ATS_CTRL , & ctrl ) ;
2011-09-27 17:57:13 +04:00
ctrl & = ~ PCI_ATS_CTRL_ENABLE ;
2015-07-17 23:15:19 +03:00
pci_write_config_word ( dev , dev - > ats_cap + PCI_ATS_CTRL , ctrl ) ;
2011-09-27 17:57:13 +04:00
2015-07-17 23:15:19 +03:00
dev - > ats_enabled = 0 ;
2011-09-27 17:57:13 +04:00
}
2019-12-19 15:03:39 +03:00
EXPORT_SYMBOL_GPL ( pci_disable_ats ) ;
2011-09-27 17:57:13 +04:00
2011-12-17 17:24:40 +04:00
void pci_restore_ats_state ( struct pci_dev * dev )
{
u16 ctrl ;
2015-07-20 17:23:37 +03:00
if ( ! dev - > ats_enabled )
2011-12-17 17:24:40 +04:00
return ;
ctrl = PCI_ATS_CTRL_ENABLE ;
if ( ! dev - > is_virtfn )
2015-07-17 23:15:19 +03:00
ctrl | = PCI_ATS_CTRL_STU ( dev - > ats_stu - PCI_ATS_MIN_STU ) ;
pci_write_config_word ( dev , dev - > ats_cap + PCI_ATS_CTRL , ctrl ) ;
2011-12-17 17:24:40 +04:00
}
2011-09-27 17:57:13 +04:00
/**
* pci_ats_queue_depth - query the ATS Invalidate Queue Depth
* @ dev : the PCI device
*
* Returns the queue depth on success , or negative on failure .
*
* The ATS spec uses 0 in the Invalidate Queue Depth field to
* indicate that the function can accept 32 Invalidate Request .
* But here we use the ` real ' values ( i . e . 1 ~ 32 ) for the Queue
* Depth ; and 0 indicates the function shares the Queue with
* other functions ( doesn ' t exclusively own a Queue ) .
*/
int pci_ats_queue_depth ( struct pci_dev * dev )
{
2015-07-20 17:24:32 +03:00
u16 cap ;
2015-07-17 23:30:26 +03:00
if ( ! dev - > ats_cap )
return - EINVAL ;
2011-09-27 17:57:13 +04:00
if ( dev - > is_virtfn )
return 0 ;
2015-07-20 17:24:32 +03:00
pci_read_config_word ( dev , dev - > ats_cap + PCI_ATS_CAP , & cap ) ;
return PCI_ATS_CAP_QDEP ( cap ) ? PCI_ATS_CAP_QDEP ( cap ) : PCI_ATS_MAX_QDEP ;
2011-09-27 17:57:13 +04:00
}
2011-09-27 17:57:15 +04:00
2019-02-19 22:06:09 +03:00
/**
* pci_ats_page_aligned - Return Page Aligned Request bit status .
* @ pdev : the PCI device
*
* Returns 1 , if the Untranslated Addresses generated by the device
* are always aligned or 0 otherwise .
*
* Per PCIe spec r4 .0 , sec 10.5 .1 .2 , if the Page Aligned Request bit
* is set , it indicates the Untranslated Addresses generated by the
* device are always aligned to a 4096 byte boundary .
*/
int pci_ats_page_aligned ( struct pci_dev * pdev )
{
u16 cap ;
if ( ! pdev - > ats_cap )
return 0 ;
pci_read_config_word ( pdev , pdev - > ats_cap + PCI_ATS_CAP , & cap ) ;
if ( cap & PCI_ATS_CAP_PAGE_ALIGNED )
return 1 ;
return 0 ;
}
2011-09-27 17:57:15 +04:00
# ifdef CONFIG_PCI_PRI
2019-09-05 22:31:45 +03:00
void pci_pri_init ( struct pci_dev * pdev )
{
2019-10-10 00:07:51 +03:00
u16 status ;
2019-09-05 22:31:45 +03:00
pdev - > pri_cap = pci_find_ext_capability ( pdev , PCI_EXT_CAP_ID_PRI ) ;
2019-10-10 00:07:51 +03:00
if ( ! pdev - > pri_cap )
return ;
pci_read_config_word ( pdev , pdev - > pri_cap + PCI_PRI_STATUS , & status ) ;
if ( status & PCI_PRI_STATUS_PASID )
pdev - > pasid_required = 1 ;
2019-09-05 22:31:45 +03:00
}
2011-09-27 17:57:15 +04:00
/**
* pci_enable_pri - Enable PRI capability
2020-07-29 23:12:19 +03:00
* @ pdev : PCI device structure
* @ reqs : outstanding requests
2011-09-27 17:57:15 +04:00
*
* Returns 0 on success , negative value on error
*/
int pci_enable_pri ( struct pci_dev * pdev , u32 reqs )
{
u16 control , status ;
u32 max_requests ;
2019-09-05 22:31:45 +03:00
int pri = pdev - > pri_cap ;
2011-09-27 17:57:15 +04:00
2019-09-05 22:31:42 +03:00
/*
* VFs must not implement the PRI Capability . If their PF
* implements PRI , it is shared by the VFs , so if the PF PRI is
* enabled , it is also enabled for the VF .
*/
if ( pdev - > is_virtfn ) {
if ( pci_physfn ( pdev ) - > pri_enabled )
return 0 ;
return - EINVAL ;
}
2017-05-30 19:25:48 +03:00
if ( WARN_ON ( pdev - > pri_enabled ) )
return - EBUSY ;
2019-09-05 22:31:45 +03:00
if ( ! pri )
2011-09-27 17:57:15 +04:00
return - EINVAL ;
2019-09-05 22:31:45 +03:00
pci_read_config_word ( pdev , pri + PCI_PRI_STATUS , & status ) ;
2017-05-30 19:25:49 +03:00
if ( ! ( status & PCI_PRI_STATUS_STOPPED ) )
2011-09-27 17:57:15 +04:00
return - EBUSY ;
2019-09-05 22:31:45 +03:00
pci_read_config_dword ( pdev , pri + PCI_PRI_MAX_REQ , & max_requests ) ;
2011-09-27 17:57:15 +04:00
reqs = min ( max_requests , reqs ) ;
2017-05-30 19:25:49 +03:00
pdev - > pri_reqs_alloc = reqs ;
2019-09-05 22:31:45 +03:00
pci_write_config_dword ( pdev , pri + PCI_PRI_ALLOC_REQ , reqs ) ;
2011-09-27 17:57:15 +04:00
2017-05-30 19:25:49 +03:00
control = PCI_PRI_CTRL_ENABLE ;
2019-09-05 22:31:45 +03:00
pci_write_config_word ( pdev , pri + PCI_PRI_CTRL , control ) ;
2011-09-27 17:57:15 +04:00
2017-05-30 19:25:48 +03:00
pdev - > pri_enabled = 1 ;
2011-09-27 17:57:15 +04:00
return 0 ;
}
/**
* pci_disable_pri - Disable PRI capability
* @ pdev : PCI device structure
*
* Only clears the enabled - bit , regardless of its former value
*/
void pci_disable_pri ( struct pci_dev * pdev )
{
u16 control ;
2019-09-05 22:31:45 +03:00
int pri = pdev - > pri_cap ;
2011-09-27 17:57:15 +04:00
2019-09-05 22:31:42 +03:00
/* VFs share the PF PRI */
if ( pdev - > is_virtfn )
return ;
2017-05-30 19:25:48 +03:00
if ( WARN_ON ( ! pdev - > pri_enabled ) )
return ;
2019-09-05 22:31:45 +03:00
if ( ! pri )
2011-09-27 17:57:15 +04:00
return ;
2019-09-05 22:31:45 +03:00
pci_read_config_word ( pdev , pri + PCI_PRI_CTRL , & control ) ;
2011-11-11 21:07:36 +04:00
control & = ~ PCI_PRI_CTRL_ENABLE ;
2019-09-05 22:31:45 +03:00
pci_write_config_word ( pdev , pri + PCI_PRI_CTRL , control ) ;
2017-05-30 19:25:48 +03:00
pdev - > pri_enabled = 0 ;
2011-09-27 17:57:15 +04:00
}
EXPORT_SYMBOL_GPL ( pci_disable_pri ) ;
2017-05-30 19:25:49 +03:00
/**
* pci_restore_pri_state - Restore PRI
* @ pdev : PCI device structure
*/
void pci_restore_pri_state ( struct pci_dev * pdev )
{
u16 control = PCI_PRI_CTRL_ENABLE ;
u32 reqs = pdev - > pri_reqs_alloc ;
2019-09-05 22:31:45 +03:00
int pri = pdev - > pri_cap ;
2017-05-30 19:25:49 +03:00
2019-09-05 22:31:42 +03:00
if ( pdev - > is_virtfn )
return ;
2017-05-30 19:25:49 +03:00
if ( ! pdev - > pri_enabled )
return ;
2019-09-05 22:31:45 +03:00
if ( ! pri )
2017-05-30 19:25:49 +03:00
return ;
2019-09-05 22:31:45 +03:00
pci_write_config_dword ( pdev , pri + PCI_PRI_ALLOC_REQ , reqs ) ;
pci_write_config_word ( pdev , pri + PCI_PRI_CTRL , control ) ;
2017-05-30 19:25:49 +03:00
}
2011-09-27 17:57:15 +04:00
/**
* pci_reset_pri - Resets device ' s PRI state
* @ pdev : PCI device structure
*
* The PRI capability must be disabled before this function is called .
* Returns 0 on success , negative value on error .
*/
int pci_reset_pri ( struct pci_dev * pdev )
{
u16 control ;
2019-09-05 22:31:45 +03:00
int pri = pdev - > pri_cap ;
2011-09-27 17:57:15 +04:00
2019-09-05 22:31:42 +03:00
if ( pdev - > is_virtfn )
return 0 ;
2017-05-30 19:25:48 +03:00
if ( WARN_ON ( pdev - > pri_enabled ) )
return - EBUSY ;
2019-09-05 22:31:45 +03:00
if ( ! pri )
2011-09-27 17:57:15 +04:00
return - EINVAL ;
2017-05-30 19:25:49 +03:00
control = PCI_PRI_CTRL_RESET ;
2019-09-05 22:31:45 +03:00
pci_write_config_word ( pdev , pri + PCI_PRI_CTRL , control ) ;
2011-09-27 17:57:15 +04:00
return 0 ;
}
2019-10-09 22:54:01 +03:00
/**
* pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
* status .
* @ pdev : PCI device structure
*
* Returns 1 if PASID is required in PRG Response Message , 0 otherwise .
*/
int pci_prg_resp_pasid_required ( struct pci_dev * pdev )
{
2019-09-05 22:31:42 +03:00
if ( pdev - > is_virtfn )
pdev = pci_physfn ( pdev ) ;
2019-10-10 00:07:51 +03:00
return pdev - > pasid_required ;
2019-10-09 22:54:01 +03:00
}
2020-07-24 01:37:29 +03:00
/**
* pci_pri_supported - Check if PRI is supported .
* @ pdev : PCI device structure
*
* Returns true if PRI capability is present , false otherwise .
*/
bool pci_pri_supported ( struct pci_dev * pdev )
{
/* VFs share the PF PRI */
if ( pci_physfn ( pdev ) - > pri_cap )
return true ;
return false ;
}
EXPORT_SYMBOL_GPL ( pci_pri_supported ) ;
2011-09-27 17:57:15 +04:00
# endif /* CONFIG_PCI_PRI */
2011-09-27 17:57:16 +04:00
# ifdef CONFIG_PCI_PASID
2019-09-05 22:31:46 +03:00
void pci_pasid_init ( struct pci_dev * pdev )
{
pdev - > pasid_cap = pci_find_ext_capability ( pdev , PCI_EXT_CAP_ID_PASID ) ;
}
2011-09-27 17:57:16 +04:00
/**
* pci_enable_pasid - Enable the PASID capability
* @ pdev : PCI device structure
* @ features : Features to enable
*
* Returns 0 on success , negative value on error . This function checks
* whether the features are actually supported by the device and returns
* an error if not .
*/
int pci_enable_pasid ( struct pci_dev * pdev , int features )
{
u16 control , supported ;
2019-09-05 22:31:46 +03:00
int pasid = pdev - > pasid_cap ;
2011-09-27 17:57:16 +04:00
2019-09-05 22:31:43 +03:00
/*
* VFs must not implement the PASID Capability , but if a PF
* supports PASID , its VFs share the PF PASID configuration .
*/
if ( pdev - > is_virtfn ) {
if ( pci_physfn ( pdev ) - > pasid_enabled )
return 0 ;
return - EINVAL ;
}
2017-05-30 19:25:48 +03:00
if ( WARN_ON ( pdev - > pasid_enabled ) )
return - EBUSY ;
2021-07-13 05:54:34 +03:00
if ( ! pdev - > eetlp_prefix_path & & ! pdev - > pasid_no_tlp )
2018-06-30 18:24:24 +03:00
return - EINVAL ;
2019-09-05 22:31:46 +03:00
if ( ! pasid )
2011-09-27 17:57:16 +04:00
return - EINVAL ;
2022-10-31 03:59:08 +03:00
if ( ! pci_acs_path_enabled ( pdev , NULL , PCI_ACS_RR | PCI_ACS_UF ) )
return - EINVAL ;
2019-09-05 22:31:46 +03:00
pci_read_config_word ( pdev , pasid + PCI_PASID_CAP , & supported ) ;
2011-11-11 21:07:36 +04:00
supported & = PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV ;
2011-09-27 17:57:16 +04:00
/* User wants to enable anything unsupported? */
if ( ( supported & features ) ! = features )
return - EINVAL ;
2011-11-11 21:07:36 +04:00
control = PCI_PASID_CTRL_ENABLE | features ;
2017-05-30 19:25:49 +03:00
pdev - > pasid_features = features ;
2011-09-27 17:57:16 +04:00
2019-09-05 22:31:46 +03:00
pci_write_config_word ( pdev , pasid + PCI_PASID_CTRL , control ) ;
2011-09-27 17:57:16 +04:00
2017-05-30 19:25:48 +03:00
pdev - > pasid_enabled = 1 ;
2011-09-27 17:57:16 +04:00
return 0 ;
}
2020-02-24 19:58:41 +03:00
EXPORT_SYMBOL_GPL ( pci_enable_pasid ) ;
2011-09-27 17:57:16 +04:00
/**
* pci_disable_pasid - Disable the PASID capability
* @ pdev : PCI device structure
*/
void pci_disable_pasid ( struct pci_dev * pdev )
{
u16 control = 0 ;
2019-09-05 22:31:46 +03:00
int pasid = pdev - > pasid_cap ;
2011-09-27 17:57:16 +04:00
2019-09-05 22:31:43 +03:00
/* VFs share the PF PASID configuration */
if ( pdev - > is_virtfn )
return ;
2017-05-30 19:25:48 +03:00
if ( WARN_ON ( ! pdev - > pasid_enabled ) )
return ;
2019-09-05 22:31:46 +03:00
if ( ! pasid )
2011-09-27 17:57:16 +04:00
return ;
2019-09-05 22:31:46 +03:00
pci_write_config_word ( pdev , pasid + PCI_PASID_CTRL , control ) ;
2017-05-30 19:25:48 +03:00
pdev - > pasid_enabled = 0 ;
2011-09-27 17:57:16 +04:00
}
2020-02-24 19:58:41 +03:00
EXPORT_SYMBOL_GPL ( pci_disable_pasid ) ;
2011-09-27 17:57:16 +04:00
2017-05-30 19:25:49 +03:00
/**
* pci_restore_pasid_state - Restore PASID capabilities
* @ pdev : PCI device structure
*/
void pci_restore_pasid_state ( struct pci_dev * pdev )
{
u16 control ;
2019-09-05 22:31:46 +03:00
int pasid = pdev - > pasid_cap ;
2017-05-30 19:25:49 +03:00
2019-09-05 22:31:43 +03:00
if ( pdev - > is_virtfn )
return ;
2017-05-30 19:25:49 +03:00
if ( ! pdev - > pasid_enabled )
return ;
2019-09-05 22:31:46 +03:00
if ( ! pasid )
2017-05-30 19:25:49 +03:00
return ;
control = PCI_PASID_CTRL_ENABLE | pdev - > pasid_features ;
2019-09-05 22:31:46 +03:00
pci_write_config_word ( pdev , pasid + PCI_PASID_CTRL , control ) ;
2017-05-30 19:25:49 +03:00
}
2011-09-27 17:57:16 +04:00
/**
* pci_pasid_features - Check which PASID features are supported
* @ pdev : PCI device structure
*
* Returns a negative value when no PASI capability is present .
* Otherwise is returns a bitmask with supported features . Current
* features reported are :
2011-11-11 21:07:36 +04:00
* PCI_PASID_CAP_EXEC - Execute permission supported
2013-11-14 22:28:18 +04:00
* PCI_PASID_CAP_PRIV - Privileged mode supported
2011-09-27 17:57:16 +04:00
*/
int pci_pasid_features ( struct pci_dev * pdev )
{
u16 supported ;
2020-01-29 22:14:00 +03:00
int pasid ;
2011-09-27 17:57:16 +04:00
2019-09-05 22:31:43 +03:00
if ( pdev - > is_virtfn )
pdev = pci_physfn ( pdev ) ;
2020-01-29 22:14:00 +03:00
pasid = pdev - > pasid_cap ;
2019-09-05 22:31:46 +03:00
if ( ! pasid )
2011-09-27 17:57:16 +04:00
return - EINVAL ;
2019-09-05 22:31:46 +03:00
pci_read_config_word ( pdev , pasid + PCI_PASID_CAP , & supported ) ;
2011-09-27 17:57:16 +04:00
2011-11-11 21:07:36 +04:00
supported & = PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV ;
2011-09-27 17:57:16 +04:00
return supported ;
}
2020-02-24 19:58:41 +03:00
EXPORT_SYMBOL_GPL ( pci_pasid_features ) ;
2011-09-27 17:57:16 +04:00
/**
2021-03-11 03:17:17 +03:00
* pci_max_pasids - Get maximum number of PASIDs supported by device
2011-09-27 17:57:16 +04:00
* @ pdev : PCI device structure
*
* Returns negative value when PASID capability is not present .
2019-05-30 16:05:58 +03:00
* Otherwise it returns the number of supported PASIDs .
2011-09-27 17:57:16 +04:00
*/
int pci_max_pasids ( struct pci_dev * pdev )
{
u16 supported ;
2020-01-29 22:14:00 +03:00
int pasid ;
2011-09-27 17:57:16 +04:00
2019-09-05 22:31:43 +03:00
if ( pdev - > is_virtfn )
pdev = pci_physfn ( pdev ) ;
2020-01-29 22:14:00 +03:00
pasid = pdev - > pasid_cap ;
2019-09-05 22:31:46 +03:00
if ( ! pasid )
2011-09-27 17:57:16 +04:00
return - EINVAL ;
2019-09-05 22:31:46 +03:00
pci_read_config_word ( pdev , pasid + PCI_PASID_CAP , & supported ) ;
2011-09-27 17:57:16 +04:00
2023-10-10 23:44:31 +03:00
return ( 1 < < FIELD_GET ( PCI_PASID_CAP_WIDTH , supported ) ) ;
2011-09-27 17:57:16 +04:00
}
2020-02-24 19:58:41 +03:00
EXPORT_SYMBOL_GPL ( pci_max_pasids ) ;
2011-09-27 17:57:16 +04:00
# endif /* CONFIG_PCI_PASID */