2018-03-28 04:22:00 +03:00
/*
* Copyright ( c ) 2018 Cumulus Networks . All rights reserved .
* Copyright ( c ) 2018 David Ahern < dsa @ cumulusnetworks . com >
2019-04-25 16:59:43 +03:00
* Copyright ( c ) 2019 Mellanox Technologies . All rights reserved .
2018-03-28 04:22:00 +03:00
*
* This software is licensed under the GNU General License Version 2 ,
* June 1991 as shown in the file COPYING in the top - level directory of this
* source tree .
*
* THE COPYRIGHT HOLDERS AND / OR OTHER PARTIES PROVIDE THE PROGRAM " AS IS "
* WITHOUT WARRANTY OF ANY KIND , EITHER EXPRESSED OR IMPLIED , INCLUDING ,
* BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE . THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
* OF THE PROGRAM IS WITH YOU . SHOULD THE PROGRAM PROVE DEFECTIVE , YOU ASSUME
* THE COST OF ALL NECESSARY SERVICING , REPAIR OR CORRECTION .
*/
2019-04-25 16:59:50 +03:00
# include <linux/debugfs.h>
2018-03-28 04:22:00 +03:00
# include <linux/device.h>
2019-04-25 16:59:53 +03:00
# include <linux/list.h>
2019-04-25 16:59:54 +03:00
# include <linux/mutex.h>
2019-04-25 16:59:51 +03:00
# include <linux/random.h>
2019-04-25 16:59:42 +03:00
# include <linux/rtnetlink.h>
2018-03-28 04:22:00 +03:00
# include <net/devlink.h>
# include "netdevsim.h"
2019-04-25 16:59:50 +03:00
static struct dentry * nsim_dev_ddir ;
static int nsim_dev_debugfs_init ( struct nsim_dev * nsim_dev )
{
2019-04-25 16:59:52 +03:00
char dev_ddir_name [ 16 ] ;
2019-04-25 16:59:50 +03:00
2019-04-25 16:59:52 +03:00
sprintf ( dev_ddir_name , DRV_NAME " %u " , nsim_dev - > nsim_bus_dev - > dev . id ) ;
2019-04-25 16:59:50 +03:00
nsim_dev - > ddir = debugfs_create_dir ( dev_ddir_name , nsim_dev_ddir ) ;
if ( IS_ERR_OR_NULL ( nsim_dev - > ddir ) )
return PTR_ERR_OR_ZERO ( nsim_dev - > ddir ) ? : - EINVAL ;
2019-04-25 16:59:52 +03:00
nsim_dev - > ports_ddir = debugfs_create_dir ( " ports " , nsim_dev - > ddir ) ;
if ( IS_ERR_OR_NULL ( nsim_dev - > ports_ddir ) )
return PTR_ERR_OR_ZERO ( nsim_dev - > ports_ddir ) ? : - EINVAL ;
2019-06-04 16:40:43 +03:00
debugfs_create_bool ( " fw_update_status " , 0600 , nsim_dev - > ddir ,
& nsim_dev - > fw_update_status ) ;
2019-04-25 16:59:50 +03:00
return 0 ;
}
static void nsim_dev_debugfs_exit ( struct nsim_dev * nsim_dev )
{
2019-04-25 16:59:52 +03:00
debugfs_remove_recursive ( nsim_dev - > ports_ddir ) ;
2019-04-25 16:59:50 +03:00
debugfs_remove_recursive ( nsim_dev - > ddir ) ;
}
2019-04-25 16:59:53 +03:00
static int nsim_dev_port_debugfs_init ( struct nsim_dev * nsim_dev ,
struct nsim_dev_port * nsim_dev_port )
{
char port_ddir_name [ 16 ] ;
char dev_link_name [ 32 ] ;
sprintf ( port_ddir_name , " %u " , nsim_dev_port - > port_index ) ;
nsim_dev_port - > ddir = debugfs_create_dir ( port_ddir_name ,
nsim_dev - > ports_ddir ) ;
if ( IS_ERR_OR_NULL ( nsim_dev_port - > ddir ) )
return - ENOMEM ;
sprintf ( dev_link_name , " ../../../ " DRV_NAME " %u " ,
nsim_dev - > nsim_bus_dev - > dev . id ) ;
debugfs_create_symlink ( " dev " , nsim_dev_port - > ddir , dev_link_name ) ;
return 0 ;
}
static void nsim_dev_port_debugfs_exit ( struct nsim_dev_port * nsim_dev_port )
{
debugfs_remove_recursive ( nsim_dev_port - > ddir ) ;
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv4_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv4_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv6_fib_resource_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static u64 nsim_dev_ipv6_fib_rules_res_occ_get ( void * priv )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = priv ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
return nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB_RULES , false ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:43 +03:00
static int nsim_dev_resources_register ( struct devlink * devlink )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03:00
struct devlink_resource_size_params params = {
. size_max = ( u64 ) - 1 ,
. size_granularity = 1 ,
. unit = DEVLINK_RESOURCE_UNIT_ENTRY
} ;
int err ;
u64 n ;
/* Resources for IPv4 */
err = devlink_resource_register ( devlink , " IPv4 " , ( u64 ) - 1 ,
NSIM_RESOURCE_IPV4 ,
DEVLINK_RESOURCE_ID_PARENT_TOP ,
2018-04-05 23:13:21 +03:00
& params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv4 top resource \n " ) ;
goto out ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV4_FIB ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv4 FIB resource \n " ) ;
return err ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV4_FIB_RULES , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV4 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv4 FIB rules resource \n " ) ;
return err ;
}
/* Resources for IPv6 */
err = devlink_resource_register ( devlink , " IPv6 " , ( u64 ) - 1 ,
NSIM_RESOURCE_IPV6 ,
DEVLINK_RESOURCE_ID_PARENT_TOP ,
2018-04-05 23:13:21 +03:00
& params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 top resource \n " ) ;
goto out ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib " , n ,
NSIM_RESOURCE_IPV6_FIB ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB resource \n " ) ;
return err ;
}
2019-04-25 16:59:43 +03:00
n = nsim_fib_get_val ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
NSIM_RESOURCE_IPV6_FIB_RULES , true ) ;
2018-03-28 04:22:00 +03:00
err = devlink_resource_register ( devlink , " fib-rules " , n ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2018-04-05 23:13:21 +03:00
NSIM_RESOURCE_IPV6 , & params ) ;
2018-03-28 04:22:00 +03:00
if ( err ) {
pr_err ( " Failed to register IPv6 FIB rules resource \n " ) ;
return err ;
}
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv4_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV4_FIB_RULES ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv4_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv6_fib_resource_occ_get ,
nsim_dev ) ;
2018-04-05 23:13:21 +03:00
devlink_resource_occ_get_register ( devlink ,
NSIM_RESOURCE_IPV6_FIB_RULES ,
2019-04-25 16:59:43 +03:00
nsim_dev_ipv6_fib_rules_res_occ_get ,
nsim_dev ) ;
2018-03-28 04:22:00 +03:00
out :
return err ;
}
2019-04-25 16:59:43 +03:00
static int nsim_dev_reload ( struct devlink * devlink ,
struct netlink_ext_ack * extack )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
2018-03-28 04:22:00 +03:00
enum nsim_resource_id res_ids [ ] = {
NSIM_RESOURCE_IPV4_FIB , NSIM_RESOURCE_IPV4_FIB_RULES ,
NSIM_RESOURCE_IPV6_FIB , NSIM_RESOURCE_IPV6_FIB_RULES
} ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( res_ids ) ; + + i ) {
int err ;
u64 val ;
err = devlink_resource_size_get ( devlink , res_ids [ i ] , & val ) ;
if ( ! err ) {
2019-04-25 16:59:43 +03:00
err = nsim_fib_set_max ( nsim_dev - > fib_data ,
2019-04-25 16:59:42 +03:00
res_ids [ i ] , val , extack ) ;
2018-03-28 04:22:00 +03:00
if ( err )
return err ;
}
}
return 0 ;
}
2019-06-04 16:40:43 +03:00
# define NSIM_DEV_FLASH_SIZE 500000
# define NSIM_DEV_FLASH_CHUNK_SIZE 1000
# define NSIM_DEV_FLASH_CHUNK_TIME_MS 10
static int nsim_dev_flash_update ( struct devlink * devlink , const char * file_name ,
const char * component ,
struct netlink_ext_ack * extack )
{
struct nsim_dev * nsim_dev = devlink_priv ( devlink ) ;
int i ;
if ( nsim_dev - > fw_update_status ) {
devlink_flash_update_begin_notify ( devlink ) ;
devlink_flash_update_status_notify ( devlink ,
" Preparing to flash " ,
component , 0 , 0 ) ;
}
for ( i = 0 ; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE ; i + + ) {
if ( nsim_dev - > fw_update_status )
devlink_flash_update_status_notify ( devlink , " Flashing " ,
component ,
i * NSIM_DEV_FLASH_CHUNK_SIZE ,
NSIM_DEV_FLASH_SIZE ) ;
msleep ( NSIM_DEV_FLASH_CHUNK_TIME_MS ) ;
}
if ( nsim_dev - > fw_update_status ) {
devlink_flash_update_status_notify ( devlink , " Flashing " ,
component ,
NSIM_DEV_FLASH_SIZE ,
NSIM_DEV_FLASH_SIZE ) ;
devlink_flash_update_status_notify ( devlink , " Flashing done " ,
component , 0 , 0 ) ;
devlink_flash_update_end_notify ( devlink ) ;
}
return 0 ;
}
2019-04-25 16:59:43 +03:00
static const struct devlink_ops nsim_dev_devlink_ops = {
. reload = nsim_dev_reload ,
2019-06-04 16:40:43 +03:00
. flash_update = nsim_dev_flash_update ,
2018-03-28 04:22:00 +03:00
} ;
2019-04-25 16:59:53 +03:00
static struct nsim_dev *
nsim_dev_create ( struct nsim_bus_dev * nsim_bus_dev , unsigned int port_count )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:43 +03:00
struct nsim_dev * nsim_dev ;
2018-03-28 04:22:00 +03:00
struct devlink * devlink ;
2018-03-30 19:28:51 +03:00
int err ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
devlink = devlink_alloc ( & nsim_dev_devlink_ops , sizeof ( * nsim_dev ) ) ;
2018-03-28 04:22:00 +03:00
if ( ! devlink )
2019-04-25 16:59:49 +03:00
return ERR_PTR ( - ENOMEM ) ;
2019-04-25 16:59:43 +03:00
nsim_dev = devlink_priv ( devlink ) ;
2019-04-25 16:59:50 +03:00
nsim_dev - > nsim_bus_dev = nsim_bus_dev ;
2019-04-25 16:59:51 +03:00
nsim_dev - > switch_id . id_len = sizeof ( nsim_dev - > switch_id . id ) ;
get_random_bytes ( nsim_dev - > switch_id . id , nsim_dev - > switch_id . id_len ) ;
2019-04-25 16:59:53 +03:00
INIT_LIST_HEAD ( & nsim_dev - > port_list ) ;
2019-04-25 16:59:54 +03:00
mutex_init ( & nsim_dev - > port_list_lock ) ;
2019-06-04 16:40:43 +03:00
nsim_dev - > fw_update_status = true ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
nsim_dev - > fib_data = nsim_fib_create ( ) ;
if ( IS_ERR ( nsim_dev - > fib_data ) ) {
err = PTR_ERR ( nsim_dev - > fib_data ) ;
2018-03-28 04:22:00 +03:00
goto err_devlink_free ;
2019-04-25 16:59:42 +03:00
}
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:43 +03:00
err = nsim_dev_resources_register ( devlink ) ;
2018-03-28 04:22:00 +03:00
if ( err )
2019-04-25 16:59:42 +03:00
goto err_fib_destroy ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:49 +03:00
err = devlink_register ( devlink , & nsim_bus_dev - > dev ) ;
2019-04-25 16:59:42 +03:00
if ( err )
goto err_resources_unregister ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:50 +03:00
err = nsim_dev_debugfs_init ( nsim_dev ) ;
if ( err )
goto err_dl_unregister ;
err = nsim_bpf_dev_init ( nsim_dev ) ;
if ( err )
goto err_debugfs_exit ;
2019-04-25 16:59:49 +03:00
return nsim_dev ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:50 +03:00
err_debugfs_exit :
nsim_dev_debugfs_exit ( nsim_dev ) ;
err_dl_unregister :
devlink_unregister ( devlink ) ;
2019-04-25 16:59:42 +03:00
err_resources_unregister :
devlink_resources_unregister ( devlink , NULL ) ;
err_fib_destroy :
2019-04-25 16:59:43 +03:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2018-03-28 04:22:00 +03:00
err_devlink_free :
devlink_free ( devlink ) ;
2019-04-25 16:59:49 +03:00
return ERR_PTR ( err ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:55 +03:00
static void nsim_dev_destroy ( struct nsim_dev * nsim_dev )
2018-03-28 04:22:00 +03:00
{
2019-04-25 16:59:49 +03:00
struct devlink * devlink = priv_to_devlink ( nsim_dev ) ;
2018-03-28 04:22:00 +03:00
2019-04-25 16:59:50 +03:00
nsim_bpf_dev_exit ( nsim_dev ) ;
nsim_dev_debugfs_exit ( nsim_dev ) ;
2019-04-25 16:59:42 +03:00
devlink_unregister ( devlink ) ;
devlink_resources_unregister ( devlink , NULL ) ;
2019-04-25 16:59:43 +03:00
nsim_fib_destroy ( nsim_dev - > fib_data ) ;
2019-04-25 16:59:54 +03:00
mutex_destroy ( & nsim_dev - > port_list_lock ) ;
2019-04-25 16:59:42 +03:00
devlink_free ( devlink ) ;
2018-03-28 04:22:00 +03:00
}
2019-04-25 16:59:50 +03:00
2019-04-25 16:59:54 +03:00
static int __nsim_dev_port_add ( struct nsim_dev * nsim_dev ,
unsigned int port_index )
2019-04-25 16:59:53 +03:00
{
struct nsim_dev_port * nsim_dev_port ;
struct devlink_port * devlink_port ;
int err ;
nsim_dev_port = kzalloc ( sizeof ( * nsim_dev_port ) , GFP_KERNEL ) ;
if ( ! nsim_dev_port )
return - ENOMEM ;
nsim_dev_port - > port_index = port_index ;
devlink_port = & nsim_dev_port - > devlink_port ;
devlink_port_attrs_set ( devlink_port , DEVLINK_PORT_FLAVOUR_PHYSICAL ,
port_index + 1 , 0 , 0 ,
nsim_dev - > switch_id . id ,
nsim_dev - > switch_id . id_len ) ;
err = devlink_port_register ( priv_to_devlink ( nsim_dev ) , devlink_port ,
port_index ) ;
if ( err )
goto err_port_free ;
err = nsim_dev_port_debugfs_init ( nsim_dev , nsim_dev_port ) ;
if ( err )
goto err_dl_port_unregister ;
2019-04-25 16:59:55 +03:00
nsim_dev_port - > ns = nsim_create ( nsim_dev , nsim_dev_port ) ;
if ( IS_ERR ( nsim_dev_port - > ns ) ) {
err = PTR_ERR ( nsim_dev_port - > ns ) ;
goto err_port_debugfs_exit ;
}
devlink_port_type_eth_set ( devlink_port , nsim_dev_port - > ns - > netdev ) ;
2019-04-25 16:59:53 +03:00
list_add ( & nsim_dev_port - > list , & nsim_dev - > port_list ) ;
return 0 ;
2019-04-25 16:59:55 +03:00
err_port_debugfs_exit :
nsim_dev_port_debugfs_exit ( nsim_dev_port ) ;
2019-04-25 16:59:53 +03:00
err_dl_port_unregister :
devlink_port_unregister ( devlink_port ) ;
err_port_free :
kfree ( nsim_dev_port ) ;
return err ;
}
2019-04-25 16:59:54 +03:00
static void __nsim_dev_port_del ( struct nsim_dev_port * nsim_dev_port )
2019-04-25 16:59:53 +03:00
{
struct devlink_port * devlink_port = & nsim_dev_port - > devlink_port ;
list_del ( & nsim_dev_port - > list ) ;
2019-04-25 16:59:55 +03:00
devlink_port_type_clear ( devlink_port ) ;
nsim_destroy ( nsim_dev_port - > ns ) ;
2019-04-25 16:59:53 +03:00
nsim_dev_port_debugfs_exit ( nsim_dev_port ) ;
devlink_port_unregister ( devlink_port ) ;
kfree ( nsim_dev_port ) ;
}
static void nsim_dev_port_del_all ( struct nsim_dev * nsim_dev )
{
struct nsim_dev_port * nsim_dev_port , * tmp ;
list_for_each_entry_safe ( nsim_dev_port , tmp ,
& nsim_dev - > port_list , list )
2019-04-25 16:59:54 +03:00
__nsim_dev_port_del ( nsim_dev_port ) ;
2019-04-25 16:59:53 +03:00
}
int nsim_dev_probe ( struct nsim_bus_dev * nsim_bus_dev )
{
struct nsim_dev * nsim_dev ;
int i ;
int err ;
nsim_dev = nsim_dev_create ( nsim_bus_dev , nsim_bus_dev - > port_count ) ;
if ( IS_ERR ( nsim_dev ) )
return PTR_ERR ( nsim_dev ) ;
dev_set_drvdata ( & nsim_bus_dev - > dev , nsim_dev ) ;
for ( i = 0 ; i < nsim_bus_dev - > port_count ; i + + ) {
2019-04-25 16:59:54 +03:00
err = __nsim_dev_port_add ( nsim_dev , i ) ;
2019-04-25 16:59:53 +03:00
if ( err )
goto err_port_del_all ;
}
return 0 ;
err_port_del_all :
nsim_dev_port_del_all ( nsim_dev ) ;
nsim_dev_destroy ( nsim_dev ) ;
return err ;
}
void nsim_dev_remove ( struct nsim_bus_dev * nsim_bus_dev )
{
struct nsim_dev * nsim_dev = dev_get_drvdata ( & nsim_bus_dev - > dev ) ;
nsim_dev_port_del_all ( nsim_dev ) ;
nsim_dev_destroy ( nsim_dev ) ;
}
2019-04-25 16:59:54 +03:00
static struct nsim_dev_port *
__nsim_dev_port_lookup ( struct nsim_dev * nsim_dev , unsigned int port_index )
{
struct nsim_dev_port * nsim_dev_port ;
list_for_each_entry ( nsim_dev_port , & nsim_dev - > port_list , list )
if ( nsim_dev_port - > port_index = = port_index )
return nsim_dev_port ;
return NULL ;
}
int nsim_dev_port_add ( struct nsim_bus_dev * nsim_bus_dev ,
unsigned int port_index )
{
struct nsim_dev * nsim_dev = dev_get_drvdata ( & nsim_bus_dev - > dev ) ;
int err ;
mutex_lock ( & nsim_dev - > port_list_lock ) ;
if ( __nsim_dev_port_lookup ( nsim_dev , port_index ) )
err = - EEXIST ;
else
err = __nsim_dev_port_add ( nsim_dev , port_index ) ;
mutex_unlock ( & nsim_dev - > port_list_lock ) ;
return err ;
}
int nsim_dev_port_del ( struct nsim_bus_dev * nsim_bus_dev ,
unsigned int port_index )
{
struct nsim_dev * nsim_dev = dev_get_drvdata ( & nsim_bus_dev - > dev ) ;
struct nsim_dev_port * nsim_dev_port ;
int err = 0 ;
mutex_lock ( & nsim_dev - > port_list_lock ) ;
nsim_dev_port = __nsim_dev_port_lookup ( nsim_dev , port_index ) ;
if ( ! nsim_dev_port )
err = - ENOENT ;
else
__nsim_dev_port_del ( nsim_dev_port ) ;
mutex_unlock ( & nsim_dev - > port_list_lock ) ;
return err ;
}
2019-04-25 16:59:50 +03:00
int nsim_dev_init ( void )
{
2019-04-25 16:59:52 +03:00
nsim_dev_ddir = debugfs_create_dir ( DRV_NAME , NULL ) ;
2019-04-25 16:59:50 +03:00
if ( IS_ERR_OR_NULL ( nsim_dev_ddir ) )
return - ENOMEM ;
return 0 ;
}
void nsim_dev_exit ( void )
{
debugfs_remove_recursive ( nsim_dev_ddir ) ;
}