2018-01-26 12:50:27 -06:00
// SPDX-License-Identifier: GPL-2.0
2020-07-29 22:12:19 +02:00
/*
2017-04-10 19:25:10 +05:30
* PCI Endpoint * Function * ( EPF ) library
*
* Copyright ( C ) 2017 Texas Instruments
* Author : Kishon Vijay Abraham I < kishon @ ti . com >
*/
# include <linux/device.h>
# include <linux/dma-mapping.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/pci-epc.h>
# include <linux/pci-epf.h>
2017-03-27 15:15:01 +05:30
# include <linux/pci-ep-cfs.h>
2017-04-10 19:25:10 +05:30
2018-04-02 18:59:35 +05:30
static DEFINE_MUTEX ( pci_epf_mutex ) ;
2024-02-04 17:28:58 -03:00
static const struct bus_type pci_epf_bus_type ;
2017-08-19 13:52:19 +05:30
static const struct device_type pci_epf_type ;
2017-04-10 19:25:10 +05:30
/**
* pci_epf_unbind ( ) - Notify the function driver that the binding between the
* EPF device and EPC device has been lost
* @ epf : the EPF device which has lost the binding with the EPC device
*
* Invoke to notify the function driver that the binding between the EPF device
* and EPC device has been lost .
*/
void pci_epf_unbind ( struct pci_epf * epf )
{
2021-08-19 18:03:37 +05:30
struct pci_epf * epf_vf ;
2017-04-10 19:25:10 +05:30
if ( ! epf - > driver ) {
dev_WARN ( & epf - > dev , " epf device not bound to driver \n " ) ;
return ;
}
2020-02-24 15:23:37 +05:30
mutex_lock ( & epf - > lock ) ;
2021-08-19 18:03:37 +05:30
list_for_each_entry ( epf_vf , & epf - > pci_vepf , list ) {
if ( epf_vf - > is_bound )
epf_vf - > driver - > ops - > unbind ( epf_vf ) ;
}
if ( epf - > is_bound )
epf - > driver - > ops - > unbind ( epf ) ;
2020-02-24 15:23:37 +05:30
mutex_unlock ( & epf - > lock ) ;
2017-04-10 19:25:10 +05:30
module_put ( epf - > driver - > owner ) ;
}
EXPORT_SYMBOL_GPL ( pci_epf_unbind ) ;
/**
* pci_epf_bind ( ) - Notify the function driver that the EPF device has been
* bound to a EPC device
* @ epf : the EPF device which has been bound to the EPC device
*
* Invoke to notify the function driver that it has been bound to a EPC device
*/
int pci_epf_bind ( struct pci_epf * epf )
{
2021-08-19 18:03:39 +05:30
struct device * dev = & epf - > dev ;
2021-08-19 18:03:37 +05:30
struct pci_epf * epf_vf ;
2021-08-19 18:03:39 +05:30
u8 func_no , vfunc_no ;
struct pci_epc * epc ;
2020-02-24 15:23:37 +05:30
int ret ;
2017-04-10 19:25:10 +05:30
if ( ! epf - > driver ) {
2021-08-19 18:03:39 +05:30
dev_WARN ( dev , " epf device not bound to driver \n " ) ;
2017-04-10 19:25:10 +05:30
return - EINVAL ;
}
if ( ! try_module_get ( epf - > driver - > owner ) )
return - EAGAIN ;
2020-02-24 15:23:37 +05:30
mutex_lock ( & epf - > lock ) ;
2021-08-19 18:03:37 +05:30
list_for_each_entry ( epf_vf , & epf - > pci_vepf , list ) {
2021-08-19 18:03:39 +05:30
vfunc_no = epf_vf - > vfunc_no ;
if ( vfunc_no < 1 ) {
dev_err ( dev , " Invalid virtual function number \n " ) ;
ret = - EINVAL ;
goto ret ;
}
epc = epf - > epc ;
func_no = epf - > func_no ;
if ( ! IS_ERR_OR_NULL ( epc ) ) {
if ( ! epc - > max_vfs ) {
dev_err ( dev , " No support for virt function \n " ) ;
ret = - EINVAL ;
goto ret ;
}
if ( vfunc_no > epc - > max_vfs [ func_no ] ) {
dev_err ( dev , " PF%d: Exceeds max vfunc number \n " ,
func_no ) ;
ret = - EINVAL ;
goto ret ;
}
}
epc = epf - > sec_epc ;
func_no = epf - > sec_epc_func_no ;
if ( ! IS_ERR_OR_NULL ( epc ) ) {
if ( ! epc - > max_vfs ) {
dev_err ( dev , " No support for virt function \n " ) ;
ret = - EINVAL ;
goto ret ;
}
if ( vfunc_no > epc - > max_vfs [ func_no ] ) {
dev_err ( dev , " PF%d: Exceeds max vfunc number \n " ,
func_no ) ;
ret = - EINVAL ;
goto ret ;
}
}
2021-08-19 18:03:37 +05:30
epf_vf - > func_no = epf - > func_no ;
2021-08-19 18:03:39 +05:30
epf_vf - > sec_epc_func_no = epf - > sec_epc_func_no ;
2021-08-19 18:03:37 +05:30
epf_vf - > epc = epf - > epc ;
epf_vf - > sec_epc = epf - > sec_epc ;
ret = epf_vf - > driver - > ops - > bind ( epf_vf ) ;
if ( ret )
goto ret ;
epf_vf - > is_bound = true ;
}
2020-02-24 15:23:37 +05:30
ret = epf - > driver - > ops - > bind ( epf ) ;
2021-08-19 18:03:37 +05:30
if ( ret )
goto ret ;
epf - > is_bound = true ;
mutex_unlock ( & epf - > lock ) ;
return 0 ;
ret :
2020-02-24 15:23:37 +05:30
mutex_unlock ( & epf - > lock ) ;
2021-08-19 18:03:37 +05:30
pci_epf_unbind ( epf ) ;
2020-02-24 15:23:37 +05:30
return ret ;
2017-04-10 19:25:10 +05:30
}
EXPORT_SYMBOL_GPL ( pci_epf_bind ) ;
2021-08-19 18:03:37 +05:30
/**
* pci_epf_add_vepf ( ) - associate virtual EP function to physical EP function
* @ epf_pf : the physical EP function to which the virtual EP function should be
* associated
* @ epf_vf : the virtual EP function to be added
*
* A physical endpoint function can be associated with multiple virtual
* endpoint functions . Invoke pci_epf_add_epf ( ) to add a virtual PCI endpoint
* function to a physical PCI endpoint function .
*/
int pci_epf_add_vepf ( struct pci_epf * epf_pf , struct pci_epf * epf_vf )
{
u32 vfunc_no ;
if ( IS_ERR_OR_NULL ( epf_pf ) | | IS_ERR_OR_NULL ( epf_vf ) )
return - EINVAL ;
if ( epf_pf - > epc | | epf_vf - > epc | | epf_vf - > epf_pf )
return - EBUSY ;
if ( epf_pf - > sec_epc | | epf_vf - > sec_epc )
return - EBUSY ;
mutex_lock ( & epf_pf - > lock ) ;
vfunc_no = find_first_zero_bit ( & epf_pf - > vfunction_num_map ,
BITS_PER_LONG ) ;
if ( vfunc_no > = BITS_PER_LONG ) {
mutex_unlock ( & epf_pf - > lock ) ;
return - EINVAL ;
}
set_bit ( vfunc_no , & epf_pf - > vfunction_num_map ) ;
epf_vf - > vfunc_no = vfunc_no ;
epf_vf - > epf_pf = epf_pf ;
epf_vf - > is_vf = true ;
list_add_tail ( & epf_vf - > list , & epf_pf - > pci_vepf ) ;
mutex_unlock ( & epf_pf - > lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( pci_epf_add_vepf ) ;
/**
* pci_epf_remove_vepf ( ) - remove virtual EP function from physical EP function
* @ epf_pf : the physical EP function from which the virtual EP function should
* be removed
* @ epf_vf : the virtual EP function to be removed
*
2021-10-06 23:38:27 +00:00
* Invoke to remove a virtual endpoint function from the physical endpoint
2021-08-19 18:03:37 +05:30
* function .
*/
void pci_epf_remove_vepf ( struct pci_epf * epf_pf , struct pci_epf * epf_vf )
{
if ( IS_ERR_OR_NULL ( epf_pf ) | | IS_ERR_OR_NULL ( epf_vf ) )
return ;
mutex_lock ( & epf_pf - > lock ) ;
clear_bit ( epf_vf - > vfunc_no , & epf_pf - > vfunction_num_map ) ;
list_del ( & epf_vf - > list ) ;
mutex_unlock ( & epf_pf - > lock ) ;
}
EXPORT_SYMBOL_GPL ( pci_epf_remove_vepf ) ;
2017-04-10 19:25:10 +05:30
/**
* pci_epf_free_space ( ) - free the allocated PCI EPF register space
2020-07-29 22:12:19 +02:00
* @ epf : the EPF device from whom to free the memory
2017-04-10 19:25:10 +05:30
* @ addr : the virtual address of the PCI EPF register space
* @ bar : the BAR number corresponding to the register space
2021-02-02 01:27:58 +05:30
* @ type : Identifies if the allocated space is for primary EPC or secondary EPC
2017-04-10 19:25:10 +05:30
*
* Invoke to free the allocated PCI EPF register space .
*/
2021-02-02 01:27:58 +05:30
void pci_epf_free_space ( struct pci_epf * epf , void * addr , enum pci_barno bar ,
enum pci_epc_interface_type type )
2017-04-10 19:25:10 +05:30
{
2021-03-26 19:09:09 +00:00
struct device * dev ;
2021-02-02 01:27:58 +05:30
struct pci_epf_bar * epf_bar ;
struct pci_epc * epc ;
2017-04-10 19:25:10 +05:30
if ( ! addr )
return ;
2021-02-02 01:27:58 +05:30
if ( type = = PRIMARY_INTERFACE ) {
epc = epf - > epc ;
epf_bar = epf - > bar ;
} else {
epc = epf - > sec_epc ;
epf_bar = epf - > sec_epc_bar ;
}
dev = epc - > dev . parent ;
dma_free_coherent ( dev , epf_bar [ bar ] . size , addr ,
epf_bar [ bar ] . phys_addr ) ;
2017-04-10 19:25:10 +05:30
2021-02-02 01:27:58 +05:30
epf_bar [ bar ] . phys_addr = 0 ;
epf_bar [ bar ] . addr = NULL ;
epf_bar [ bar ] . size = 0 ;
epf_bar [ bar ] . barno = 0 ;
epf_bar [ bar ] . flags = 0 ;
2017-04-10 19:25:10 +05:30
}
EXPORT_SYMBOL_GPL ( pci_epf_free_space ) ;
/**
* pci_epf_alloc_space ( ) - allocate memory for the PCI EPF register space
2020-07-29 22:12:19 +02:00
* @ epf : the EPF device to whom allocate the memory
2017-04-10 19:25:10 +05:30
* @ size : the size of the memory that has to be allocated
* @ bar : the BAR number corresponding to the allocated register space
2024-02-07 22:39:14 +01:00
* @ epc_features : the features provided by the EPC specific to this EPF
2021-02-02 01:27:58 +05:30
* @ type : Identifies if the allocation is for primary EPC or secondary EPC
2017-04-10 19:25:10 +05:30
*
* Invoke to allocate memory for the PCI EPF register space .
2024-03-20 12:31:49 +01:00
* Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR
* can only be a 64 - bit BAR , or if the requested size is larger than 2 GB .
2017-04-10 19:25:10 +05:30
*/
2019-03-25 15:09:39 +05:30
void * pci_epf_alloc_space ( struct pci_epf * epf , size_t size , enum pci_barno bar ,
2024-02-07 22:39:14 +01:00
const struct pci_epc_features * epc_features ,
enum pci_epc_interface_type type )
2017-04-10 19:25:10 +05:30
{
2024-02-16 14:45:14 +01:00
u64 bar_fixed_size = epc_features - > bar [ bar ] . fixed_size ;
2024-02-07 22:39:14 +01:00
size_t align = epc_features - > align ;
2021-02-02 01:27:58 +05:30
struct pci_epf_bar * epf_bar ;
2017-04-10 19:25:10 +05:30
dma_addr_t phys_addr ;
2021-02-02 01:27:58 +05:30
struct pci_epc * epc ;
struct device * dev ;
void * space ;
2017-04-10 19:25:10 +05:30
if ( size < 128 )
size = 128 ;
2019-03-25 15:09:39 +05:30
2024-02-16 14:45:14 +01:00
if ( epc_features - > bar [ bar ] . type = = BAR_FIXED & & bar_fixed_size ) {
if ( size > bar_fixed_size ) {
dev_err ( & epf - > dev ,
" requested BAR size is larger than fixed size \n " ) ;
return NULL ;
}
2024-02-07 22:39:15 +01:00
size = bar_fixed_size ;
2024-02-16 14:45:14 +01:00
}
2024-02-07 22:39:15 +01:00
2019-03-25 15:09:39 +05:30
if ( align )
size = ALIGN ( size , align ) ;
else
size = roundup_pow_of_two ( size ) ;
2017-04-10 19:25:10 +05:30
2021-02-02 01:27:58 +05:30
if ( type = = PRIMARY_INTERFACE ) {
epc = epf - > epc ;
epf_bar = epf - > bar ;
} else {
epc = epf - > sec_epc ;
epf_bar = epf - > sec_epc_bar ;
}
dev = epc - > dev . parent ;
2017-04-10 19:25:10 +05:30
space = dma_alloc_coherent ( dev , size , & phys_addr , GFP_KERNEL ) ;
if ( ! space ) {
dev_err ( dev , " failed to allocate mem space \n " ) ;
return NULL ;
}
2021-02-02 01:27:58 +05:30
epf_bar [ bar ] . phys_addr = phys_addr ;
epf_bar [ bar ] . addr = space ;
epf_bar [ bar ] . size = size ;
epf_bar [ bar ] . barno = bar ;
2024-03-20 12:31:49 +01:00
if ( upper_32_bits ( size ) | | epc_features - > bar [ bar ] . only_64bit )
epf_bar [ bar ] . flags | = PCI_BASE_ADDRESS_MEM_TYPE_64 ;
else
epf_bar [ bar ] . flags | = PCI_BASE_ADDRESS_MEM_TYPE_32 ;
2017-04-10 19:25:10 +05:30
return space ;
}
EXPORT_SYMBOL_GPL ( pci_epf_alloc_space ) ;
2018-07-09 15:18:56 -05:00
static void pci_epf_remove_cfs ( struct pci_epf_driver * driver )
2017-04-10 19:25:10 +05:30
{
2018-06-29 13:49:24 -05:00
struct config_group * group , * tmp ;
2018-04-02 18:59:35 +05:30
2018-07-09 15:18:56 -05:00
if ( ! IS_ENABLED ( CONFIG_PCI_ENDPOINT_CONFIGFS ) )
return ;
2018-04-02 18:59:35 +05:30
mutex_lock ( & pci_epf_mutex ) ;
2018-06-29 13:49:24 -05:00
list_for_each_entry_safe ( group , tmp , & driver - > epf_group , group_entry )
2018-04-02 18:59:35 +05:30
pci_ep_cfs_remove_epf_group ( group ) ;
list_del ( & driver - > epf_group ) ;
mutex_unlock ( & pci_epf_mutex ) ;
2018-07-09 15:18:56 -05:00
}
/**
* pci_epf_unregister_driver ( ) - unregister the PCI EPF driver
* @ driver : the PCI EPF driver that has to be unregistered
*
* Invoke to unregister the PCI EPF driver .
*/
void pci_epf_unregister_driver ( struct pci_epf_driver * driver )
{
pci_epf_remove_cfs ( driver ) ;
2017-04-10 19:25:10 +05:30
driver_unregister ( & driver - > driver ) ;
}
EXPORT_SYMBOL_GPL ( pci_epf_unregister_driver ) ;
2018-07-09 15:18:56 -05:00
static int pci_epf_add_cfs ( struct pci_epf_driver * driver )
{
struct config_group * group ;
const struct pci_epf_device_id * id ;
if ( ! IS_ENABLED ( CONFIG_PCI_ENDPOINT_CONFIGFS ) )
return 0 ;
INIT_LIST_HEAD ( & driver - > epf_group ) ;
id = driver - > id_table ;
while ( id - > name [ 0 ] ) {
group = pci_ep_cfs_add_epf_group ( id - > name ) ;
if ( IS_ERR ( group ) ) {
pci_epf_remove_cfs ( driver ) ;
return PTR_ERR ( group ) ;
}
mutex_lock ( & pci_epf_mutex ) ;
list_add_tail ( & group - > group_entry , & driver - > epf_group ) ;
mutex_unlock ( & pci_epf_mutex ) ;
id + + ;
}
return 0 ;
}
2017-04-10 19:25:10 +05:30
/**
* __pci_epf_register_driver ( ) - register a new PCI EPF driver
* @ driver : structure representing PCI EPF driver
* @ owner : the owner of the module that registers the PCI EPF driver
*
* Invoke to register a new PCI EPF driver .
*/
int __pci_epf_register_driver ( struct pci_epf_driver * driver ,
struct module * owner )
{
int ret ;
if ( ! driver - > ops )
return - EINVAL ;
2020-02-24 15:23:34 +05:30
if ( ! driver - > ops - > bind | | ! driver - > ops - > unbind )
2017-04-10 19:25:10 +05:30
return - EINVAL ;
driver - > driver . bus = & pci_epf_bus_type ;
driver - > driver . owner = owner ;
ret = driver_register ( & driver - > driver ) ;
if ( ret )
return ret ;
2018-07-09 15:18:56 -05:00
pci_epf_add_cfs ( driver ) ;
2017-03-27 15:15:01 +05:30
2017-04-10 19:25:10 +05:30
return 0 ;
}
EXPORT_SYMBOL_GPL ( __pci_epf_register_driver ) ;
/**
* pci_epf_destroy ( ) - destroy the created PCI EPF device
* @ epf : the PCI EPF device that has to be destroyed .
*
* Invoke to destroy the PCI EPF device created by invoking pci_epf_create ( ) .
*/
void pci_epf_destroy ( struct pci_epf * epf )
{
device_unregister ( & epf - > dev ) ;
}
EXPORT_SYMBOL_GPL ( pci_epf_destroy ) ;
/**
* pci_epf_create ( ) - create a new PCI EPF device
* @ name : the name of the PCI EPF device . This name will be used to bind the
2021-10-06 23:38:27 +00:00
* EPF device to a EPF driver
2017-04-10 19:25:10 +05:30
*
* Invoke to create a new PCI EPF device by providing the name of the function
* device .
*/
struct pci_epf * pci_epf_create ( const char * name )
{
int ret ;
struct pci_epf * epf ;
struct device * dev ;
2018-02-28 18:32:18 +01:00
int len ;
2017-04-10 19:25:10 +05:30
epf = kzalloc ( sizeof ( * epf ) , GFP_KERNEL ) ;
2018-02-28 18:32:20 +01:00
if ( ! epf )
return ERR_PTR ( - ENOMEM ) ;
2017-04-10 19:25:10 +05:30
2018-02-28 18:32:18 +01:00
len = strchrnul ( name , ' . ' ) - name ;
epf - > name = kstrndup ( name , len , GFP_KERNEL ) ;
2017-04-10 19:25:10 +05:30
if ( ! epf - > name ) {
2018-02-28 18:32:20 +01:00
kfree ( epf ) ;
return ERR_PTR ( - ENOMEM ) ;
2017-04-10 19:25:10 +05:30
}
2021-08-19 18:03:37 +05:30
/* VFs are numbered starting with 1. So set BIT(0) by default */
epf - > vfunction_num_map = 1 ;
INIT_LIST_HEAD ( & epf - > pci_vepf ) ;
2017-04-10 19:25:10 +05:30
dev = & epf - > dev ;
device_initialize ( dev ) ;
dev - > bus = & pci_epf_bus_type ;
dev - > type = & pci_epf_type ;
2020-02-24 15:23:37 +05:30
mutex_init ( & epf - > lock ) ;
2017-04-10 19:25:10 +05:30
ret = dev_set_name ( dev , " %s " , name ) ;
2018-02-28 18:32:20 +01:00
if ( ret ) {
put_device ( dev ) ;
return ERR_PTR ( ret ) ;
}
2017-04-10 19:25:10 +05:30
ret = device_add ( dev ) ;
2018-02-28 18:32:20 +01:00
if ( ret ) {
put_device ( dev ) ;
return ERR_PTR ( ret ) ;
}
2017-04-10 19:25:10 +05:30
return epf ;
}
EXPORT_SYMBOL_GPL ( pci_epf_create ) ;
static void pci_epf_dev_release ( struct device * dev )
{
struct pci_epf * epf = to_pci_epf ( dev ) ;
kfree ( epf - > name ) ;
kfree ( epf ) ;
}
2017-08-19 13:52:19 +05:30
static const struct device_type pci_epf_type = {
2017-04-10 19:25:10 +05:30
. release = pci_epf_dev_release ,
} ;
2023-06-02 17:17:49 +05:30
static const struct pci_epf_device_id *
2017-04-10 19:25:10 +05:30
pci_epf_match_id ( const struct pci_epf_device_id * id , const struct pci_epf * epf )
{
while ( id - > name [ 0 ] ) {
if ( strcmp ( epf - > name , id - > name ) = = 0 )
2023-06-02 17:17:49 +05:30
return id ;
2017-04-10 19:25:10 +05:30
id + + ;
}
2023-06-02 17:17:49 +05:30
return NULL ;
2017-04-10 19:25:10 +05:30
}
static int pci_epf_device_match ( struct device * dev , struct device_driver * drv )
{
struct pci_epf * epf = to_pci_epf ( dev ) ;
struct pci_epf_driver * driver = to_pci_epf_driver ( drv ) ;
if ( driver - > id_table )
2023-06-02 17:17:49 +05:30
return ! ! pci_epf_match_id ( driver - > id_table , epf ) ;
2017-04-10 19:25:10 +05:30
return ! strcmp ( epf - > name , drv - > name ) ;
}
static int pci_epf_device_probe ( struct device * dev )
{
struct pci_epf * epf = to_pci_epf ( dev ) ;
struct pci_epf_driver * driver = to_pci_epf_driver ( dev - > driver ) ;
if ( ! driver - > probe )
return - ENODEV ;
epf - > driver = driver ;
2023-06-02 17:17:49 +05:30
return driver - > probe ( epf , pci_epf_match_id ( driver - > id_table , epf ) ) ;
2017-04-10 19:25:10 +05:30
}
2021-07-13 21:35:22 +02:00
static void pci_epf_device_remove ( struct device * dev )
2017-04-10 19:25:10 +05:30
{
struct pci_epf * epf = to_pci_epf ( dev ) ;
struct pci_epf_driver * driver = to_pci_epf_driver ( dev - > driver ) ;
2017-08-18 20:27:55 +05:30
if ( driver - > remove )
2021-07-13 21:35:18 +02:00
driver - > remove ( epf ) ;
2017-04-10 19:25:10 +05:30
epf - > driver = NULL ;
}
2024-02-04 17:28:58 -03:00
static const struct bus_type pci_epf_bus_type = {
2017-04-10 19:25:10 +05:30
. name = " pci-epf " ,
. match = pci_epf_device_match ,
. probe = pci_epf_device_probe ,
. remove = pci_epf_device_remove ,
} ;
static int __init pci_epf_init ( void )
{
int ret ;
ret = bus_register ( & pci_epf_bus_type ) ;
if ( ret ) {
pr_err ( " failed to register pci epf bus --> %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
module_init ( pci_epf_init ) ;
static void __exit pci_epf_exit ( void )
{
bus_unregister ( & pci_epf_bus_type ) ;
}
module_exit ( pci_epf_exit ) ;
MODULE_DESCRIPTION ( " PCI EPF Library " ) ;
MODULE_AUTHOR ( " Kishon Vijay Abraham I <kishon@ti.com> " ) ;