2010-03-30 17:56:24 +04:00
/*
* Copyright ( C ) ST - Ericsson AB 2010
* Author : Sjur Brendeland / sjur . brandeland @ stericsson . com
* License terms : GNU General Public License ( GPL ) version 2
*/
2010-09-06 01:31:11 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
2010-03-30 17:56:24 +04:00
# include <linux/kernel.h>
# include <linux/stddef.h>
2010-04-01 11:28:49 +04:00
# include <linux/slab.h>
2010-06-17 10:55:40 +04:00
# include <linux/netdevice.h>
2011-05-13 06:44:01 +04:00
# include <linux/module.h>
2010-03-30 17:56:24 +04:00
# include <net/caif/caif_layer.h>
# include <net/caif/cfpkt.h>
# include <net/caif/cfcnfg.h>
# include <net/caif/cfctrl.h>
# include <net/caif/cfmuxl.h>
# include <net/caif/cffrml.h>
# include <net/caif/cfserl.h>
# include <net/caif/cfsrvl.h>
2011-05-13 06:44:01 +04:00
# include <net/caif/caif_dev.h>
2010-03-30 17:56:24 +04:00
# define container_obj(layr) container_of(layr, struct cfcnfg, layer)
/* Information about CAIF physical interfaces held by Config Module in order
* to manage physical interfaces
*/
struct cfcnfg_phyinfo {
2011-05-13 06:44:01 +04:00
struct list_head node ;
bool up ;
2010-03-30 17:56:24 +04:00
/* Pointer to the layer below the MUX (framing layer) */
struct cflayer * frm_layer ;
/* Pointer to the lowest actual physical layer */
struct cflayer * phy_layer ;
/* Unique identifier of the physical interface */
unsigned int id ;
/* Preference of the physical in interface */
enum cfcnfg_phy_preference pref ;
/* Information about the physical device */
struct dev_info dev_info ;
2010-06-17 10:55:40 +04:00
/* Interface index */
int ifindex ;
/* Use Start of frame extension */
bool use_stx ;
/* Use Start of frame checksum */
bool use_fcs ;
2010-03-30 17:56:24 +04:00
} ;
struct cfcnfg {
struct cflayer layer ;
struct cflayer * ctrl ;
struct cflayer * mux ;
2011-05-13 06:44:01 +04:00
struct list_head phys ;
struct mutex lock ;
2010-03-30 17:56:24 +04:00
} ;
2010-04-28 12:54:35 +04:00
static void cfcnfg_linkup_rsp ( struct cflayer * layer , u8 channel_id ,
2010-03-30 17:56:24 +04:00
enum cfctrl_srv serv , u8 phyid ,
struct cflayer * adapt_layer ) ;
2010-04-28 12:54:37 +04:00
static void cfcnfg_linkdestroy_rsp ( struct cflayer * layer , u8 channel_id ) ;
2010-04-28 12:54:35 +04:00
static void cfcnfg_reject_rsp ( struct cflayer * layer , u8 channel_id ,
2010-03-30 17:56:24 +04:00
struct cflayer * adapt_layer ) ;
static void cfctrl_resp_func ( void ) ;
static void cfctrl_enum_resp ( void ) ;
struct cfcnfg * cfcnfg_create ( void )
{
struct cfcnfg * this ;
struct cfctrl_rsp * resp ;
2011-05-13 06:44:01 +04:00
might_sleep ( ) ;
2010-03-30 17:56:24 +04:00
/* Initiate this layer */
2010-05-13 14:03:32 +04:00
this = kzalloc ( sizeof ( struct cfcnfg ) , GFP_ATOMIC ) ;
2010-03-30 17:56:24 +04:00
if ( ! this ) {
2010-09-06 01:31:11 +04:00
pr_warn ( " Out of memory \n " ) ;
2010-03-30 17:56:24 +04:00
return NULL ;
}
this - > mux = cfmuxl_create ( ) ;
if ( ! this - > mux )
goto out_of_mem ;
this - > ctrl = cfctrl_create ( ) ;
if ( ! this - > ctrl )
goto out_of_mem ;
/* Initiate response functions */
resp = cfctrl_get_respfuncs ( this - > ctrl ) ;
resp - > enum_rsp = cfctrl_enum_resp ;
resp - > linkerror_ind = cfctrl_resp_func ;
2010-04-28 12:54:35 +04:00
resp - > linkdestroy_rsp = cfcnfg_linkdestroy_rsp ;
2010-03-30 17:56:24 +04:00
resp - > sleep_rsp = cfctrl_resp_func ;
resp - > wake_rsp = cfctrl_resp_func ;
resp - > restart_rsp = cfctrl_resp_func ;
resp - > radioset_rsp = cfctrl_resp_func ;
2010-04-28 12:54:35 +04:00
resp - > linksetup_rsp = cfcnfg_linkup_rsp ;
resp - > reject_rsp = cfcnfg_reject_rsp ;
2011-05-13 06:44:01 +04:00
INIT_LIST_HEAD ( & this - > phys ) ;
2010-03-30 17:56:24 +04:00
cfmuxl_set_uplayer ( this - > mux , this - > ctrl , 0 ) ;
layer_set_dn ( this - > ctrl , this - > mux ) ;
layer_set_up ( this - > ctrl , this ) ;
2011-05-13 06:44:01 +04:00
mutex_init ( & this - > lock ) ;
2010-03-30 17:56:24 +04:00
return this ;
out_of_mem :
2010-09-06 01:31:11 +04:00
pr_warn ( " Out of memory \n " ) ;
2011-05-13 06:44:01 +04:00
synchronize_rcu ( ) ;
2010-03-30 17:56:24 +04:00
kfree ( this - > mux ) ;
kfree ( this - > ctrl ) ;
kfree ( this ) ;
return NULL ;
}
EXPORT_SYMBOL ( cfcnfg_create ) ;
void cfcnfg_remove ( struct cfcnfg * cfg )
{
2011-05-13 06:44:01 +04:00
might_sleep ( ) ;
2010-03-30 17:56:24 +04:00
if ( cfg ) {
2011-05-13 06:44:01 +04:00
synchronize_rcu ( ) ;
2010-03-30 17:56:24 +04:00
kfree ( cfg - > mux ) ;
kfree ( cfg - > ctrl ) ;
kfree ( cfg ) ;
}
}
static void cfctrl_resp_func ( void )
{
}
2011-05-13 06:44:01 +04:00
static struct cfcnfg_phyinfo * cfcnfg_get_phyinfo_rcu ( struct cfcnfg * cnfg ,
u8 phyid )
{
struct cfcnfg_phyinfo * phy ;
list_for_each_entry_rcu ( phy , & cnfg - > phys , node )
if ( phy - > id = = phyid )
return phy ;
return NULL ;
}
2010-03-30 17:56:24 +04:00
static void cfctrl_enum_resp ( void )
{
}
struct dev_info * cfcnfg_get_phyid ( struct cfcnfg * cnfg ,
enum cfcnfg_phy_preference phy_pref )
{
/* Try to match with specified preference */
2011-05-13 06:44:01 +04:00
struct cfcnfg_phyinfo * phy ;
list_for_each_entry_rcu ( phy , & cnfg - > phys , node ) {
if ( phy - > up & & phy - > pref = = phy_pref & &
phy - > frm_layer ! = NULL )
return & phy - > dev_info ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
/* Otherwise just return something */
list_for_each_entry_rcu ( phy , & cnfg - > phys , node )
if ( phy - > up )
return & phy - > dev_info ;
2010-03-30 17:56:24 +04:00
return NULL ;
}
2010-11-01 14:52:47 +03:00
int cfcnfg_get_id_from_ifi ( struct cfcnfg * cnfg , int ifi )
2010-03-30 17:56:24 +04:00
{
2011-05-13 06:44:01 +04:00
struct cfcnfg_phyinfo * phy ;
list_for_each_entry_rcu ( phy , & cnfg - > phys , node )
if ( phy - > ifindex = = ifi & & phy - > up )
return phy - > id ;
2010-11-01 14:52:47 +03:00
return - ENODEV ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
int cfcnfg_disconn_adapt_layer ( struct cfcnfg * cfg , struct cflayer * adap_layer )
2010-03-30 17:56:24 +04:00
{
u8 channel_id = 0 ;
int ret = 0 ;
2010-04-28 12:54:37 +04:00
struct cflayer * servl = NULL ;
2011-01-15 06:06:39 +03:00
2010-03-30 17:56:24 +04:00
caif_assert ( adap_layer ! = NULL ) ;
2011-05-13 06:44:01 +04:00
2010-03-30 17:56:24 +04:00
channel_id = adap_layer - > id ;
2010-04-28 12:54:37 +04:00
if ( adap_layer - > dn = = NULL | | channel_id = = 0 ) {
2010-09-21 15:44:44 +04:00
pr_err ( " adap_layer->dn == NULL or adap_layer->id is 0 \n " ) ;
2010-03-30 17:56:24 +04:00
ret = - ENOTCONN ;
goto end ;
}
2011-05-13 06:44:01 +04:00
servl = cfmuxl_remove_uplayer ( cfg - > mux , channel_id ) ;
2010-04-28 12:54:37 +04:00
if ( servl = = NULL ) {
2011-05-13 06:44:01 +04:00
pr_err ( " PROTOCOL ERROR - "
" Error removing service_layer Channel_Id(%d) " ,
channel_id ) ;
2010-03-30 17:56:24 +04:00
ret = - EINVAL ;
goto end ;
}
2011-05-13 06:44:01 +04:00
ret = cfctrl_linkdown_req ( cfg - > ctrl , channel_id , adap_layer ) ;
2010-04-28 12:54:37 +04:00
end :
2011-05-13 06:44:01 +04:00
cfctrl_cancel_req ( cfg - > ctrl , adap_layer ) ;
/* Do RCU sync before initiating cleanup */
synchronize_rcu ( ) ;
2010-04-28 12:54:37 +04:00
if ( adap_layer - > ctrlcmd ! = NULL )
adap_layer - > ctrlcmd ( adap_layer , CAIF_CTRLCMD_DEINIT_RSP , 0 ) ;
2010-03-30 17:56:24 +04:00
return ret ;
}
2010-04-28 12:54:35 +04:00
EXPORT_SYMBOL ( cfcnfg_disconn_adapt_layer ) ;
2010-03-30 17:56:24 +04:00
2010-04-28 12:54:36 +04:00
void cfcnfg_release_adap_layer ( struct cflayer * adap_layer )
{
if ( adap_layer - > dn )
cfsrvl_put ( adap_layer - > dn ) ;
}
EXPORT_SYMBOL ( cfcnfg_release_adap_layer ) ;
2010-04-28 12:54:37 +04:00
static void cfcnfg_linkdestroy_rsp ( struct cflayer * layer , u8 channel_id )
2010-03-30 17:56:24 +04:00
{
}
2011-04-11 14:43:50 +04:00
static const int protohead [ CFCTRL_SRV_MASK ] = {
2010-06-17 10:55:40 +04:00
[ CFCTRL_SRV_VEI ] = 4 ,
[ CFCTRL_SRV_DATAGRAM ] = 7 ,
[ CFCTRL_SRV_UTIL ] = 4 ,
[ CFCTRL_SRV_RFM ] = 3 ,
[ CFCTRL_SRV_DBG ] = 3 ,
} ;
2010-04-28 12:54:37 +04:00
int cfcnfg_add_adaptation_layer ( struct cfcnfg * cnfg ,
2010-03-30 17:56:24 +04:00
struct cfctrl_link_param * param ,
2010-06-17 10:55:40 +04:00
struct cflayer * adap_layer ,
int * ifindex ,
int * proto_head ,
int * proto_tail )
2010-03-30 17:56:24 +04:00
{
struct cflayer * frml ;
2011-05-13 06:44:01 +04:00
struct cfcnfg_phyinfo * phy ;
int err ;
rcu_read_lock ( ) ;
phy = cfcnfg_get_phyinfo_rcu ( cnfg , param - > phyid ) ;
if ( ! phy ) {
err = - ENODEV ;
goto unlock ;
}
err = - EINVAL ;
2010-03-30 17:56:24 +04:00
if ( adap_layer = = NULL ) {
2010-09-06 01:31:11 +04:00
pr_err ( " adap_layer is zero \n " ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
if ( adap_layer - > receive = = NULL ) {
2010-09-06 01:31:11 +04:00
pr_err ( " adap_layer->receive is NULL \n " ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
if ( adap_layer - > ctrlcmd = = NULL ) {
2010-09-06 01:31:11 +04:00
pr_err ( " adap_layer->ctrlcmd == NULL \n " ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
err = - ENODEV ;
frml = phy - > frm_layer ;
2010-03-30 17:56:24 +04:00
if ( frml = = NULL ) {
2010-09-06 01:31:11 +04:00
pr_err ( " Specified PHY type does not exist! \n " ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
caif_assert ( param - > phyid = = phy - > id ) ;
caif_assert ( phy - > frm_layer - > id = =
2010-03-30 17:56:24 +04:00
param - > phyid ) ;
2011-05-13 06:44:01 +04:00
caif_assert ( phy - > phy_layer - > id = =
2010-03-30 17:56:24 +04:00
param - > phyid ) ;
2010-06-17 10:55:40 +04:00
2011-05-13 06:44:01 +04:00
* ifindex = phy - > ifindex ;
* proto_tail = 2 ;
2010-06-17 10:55:40 +04:00
* proto_head =
2011-05-13 06:44:01 +04:00
protohead [ param - > linktype ] + ( phy - > use_stx ? 1 : 0 ) ;
2010-06-17 10:55:40 +04:00
2011-05-13 06:44:01 +04:00
rcu_read_unlock ( ) ;
2010-06-17 10:55:40 +04:00
2010-03-30 17:56:24 +04:00
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
cfctrl_enum_req ( cnfg - > ctrl , param - > phyid ) ;
2010-04-28 12:54:37 +04:00
return cfctrl_linkup_request ( cnfg - > ctrl , param , adap_layer ) ;
2011-05-13 06:44:01 +04:00
unlock :
rcu_read_unlock ( ) ;
return err ;
2010-03-30 17:56:24 +04:00
}
EXPORT_SYMBOL ( cfcnfg_add_adaptation_layer ) ;
2010-04-28 12:54:35 +04:00
static void cfcnfg_reject_rsp ( struct cflayer * layer , u8 channel_id ,
2010-03-30 17:56:24 +04:00
struct cflayer * adapt_layer )
{
if ( adapt_layer ! = NULL & & adapt_layer - > ctrlcmd ! = NULL )
adapt_layer - > ctrlcmd ( adapt_layer ,
CAIF_CTRLCMD_INIT_FAIL_RSP , 0 ) ;
}
static void
2010-04-28 12:54:35 +04:00
cfcnfg_linkup_rsp ( struct cflayer * layer , u8 channel_id , enum cfctrl_srv serv ,
2011-05-13 06:44:01 +04:00
u8 phyid , struct cflayer * adapt_layer )
2010-03-30 17:56:24 +04:00
{
struct cfcnfg * cnfg = container_obj ( layer ) ;
struct cflayer * servicel = NULL ;
struct cfcnfg_phyinfo * phyinfo ;
2010-06-17 10:55:40 +04:00
struct net_device * netdev ;
2011-05-13 06:44:01 +04:00
rcu_read_lock ( ) ;
2010-03-30 17:56:24 +04:00
if ( adapt_layer = = NULL ) {
2011-05-13 06:44:01 +04:00
pr_debug ( " link setup response but no client exist, "
" send linkdown back \n " ) ;
2010-04-28 12:54:37 +04:00
cfctrl_linkdown_req ( cnfg - > ctrl , channel_id , NULL ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
caif_assert ( cnfg ! = NULL ) ;
caif_assert ( phyid ! = 0 ) ;
2011-05-13 06:44:01 +04:00
phyinfo = cfcnfg_get_phyinfo_rcu ( cnfg , phyid ) ;
if ( phyinfo = = NULL ) {
pr_err ( " ERROR: Link Layer Device dissapeared "
" while connecting \n " ) ;
goto unlock ;
}
caif_assert ( phyinfo ! = NULL ) ;
2010-03-30 17:56:24 +04:00
caif_assert ( phyinfo - > id = = phyid ) ;
caif_assert ( phyinfo - > phy_layer ! = NULL ) ;
caif_assert ( phyinfo - > phy_layer - > id = = phyid ) ;
2010-04-28 12:54:35 +04:00
adapt_layer - > id = channel_id ;
2010-03-30 17:56:24 +04:00
switch ( serv ) {
case CFCTRL_SRV_VEI :
2010-04-28 12:54:35 +04:00
servicel = cfvei_create ( channel_id , & phyinfo - > dev_info ) ;
2010-03-30 17:56:24 +04:00
break ;
case CFCTRL_SRV_DATAGRAM :
2011-05-13 06:44:01 +04:00
servicel = cfdgml_create ( channel_id ,
& phyinfo - > dev_info ) ;
2010-03-30 17:56:24 +04:00
break ;
case CFCTRL_SRV_RFM :
2010-06-17 10:55:40 +04:00
netdev = phyinfo - > dev_info . dev ;
2010-06-17 10:55:39 +04:00
servicel = cfrfml_create ( channel_id , & phyinfo - > dev_info ,
2010-06-17 10:55:40 +04:00
netdev - > mtu ) ;
2010-03-30 17:56:24 +04:00
break ;
case CFCTRL_SRV_UTIL :
2010-04-28 12:54:35 +04:00
servicel = cfutill_create ( channel_id , & phyinfo - > dev_info ) ;
2010-03-30 17:56:24 +04:00
break ;
case CFCTRL_SRV_VIDEO :
2010-04-28 12:54:35 +04:00
servicel = cfvidl_create ( channel_id , & phyinfo - > dev_info ) ;
2010-03-30 17:56:24 +04:00
break ;
case CFCTRL_SRV_DBG :
2010-04-28 12:54:35 +04:00
servicel = cfdbgl_create ( channel_id , & phyinfo - > dev_info ) ;
2010-03-30 17:56:24 +04:00
break ;
default :
2011-05-13 06:44:01 +04:00
pr_err ( " Protocol error. Link setup response "
" - unknown channel type \n " ) ;
goto unlock ;
2010-03-30 17:56:24 +04:00
}
if ( ! servicel ) {
2010-09-06 01:31:11 +04:00
pr_warn ( " Out of memory \n " ) ;
2011-05-13 06:44:01 +04:00
goto unlock ;
2010-03-30 17:56:24 +04:00
}
layer_set_dn ( servicel , cnfg - > mux ) ;
2010-04-28 12:54:35 +04:00
cfmuxl_set_uplayer ( cnfg - > mux , servicel , channel_id ) ;
2010-03-30 17:56:24 +04:00
layer_set_up ( servicel , adapt_layer ) ;
layer_set_dn ( adapt_layer , servicel ) ;
2011-05-13 06:44:01 +04:00
rcu_read_unlock ( ) ;
2010-03-30 17:56:24 +04:00
servicel - > ctrlcmd ( servicel , CAIF_CTRLCMD_INIT_RSP , 0 ) ;
2011-05-13 06:44:01 +04:00
return ;
unlock :
rcu_read_unlock ( ) ;
2010-03-30 17:56:24 +04:00
}
void
cfcnfg_add_phy_layer ( struct cfcnfg * cnfg , enum cfcnfg_phy_type phy_type ,
2010-06-17 10:55:40 +04:00
struct net_device * dev , struct cflayer * phy_layer ,
2011-05-13 06:44:01 +04:00
u16 * phy_id , enum cfcnfg_phy_preference pref ,
2010-03-30 17:56:24 +04:00
bool fcs , bool stx )
{
struct cflayer * frml ;
struct cflayer * phy_driver = NULL ;
2011-05-13 06:44:01 +04:00
struct cfcnfg_phyinfo * phyinfo ;
2010-03-30 17:56:24 +04:00
int i ;
2011-05-13 06:44:01 +04:00
u8 phyid ;
2010-03-30 17:56:24 +04:00
2011-05-13 06:44:01 +04:00
mutex_lock ( & cnfg - > lock ) ;
2010-03-30 17:56:24 +04:00
2011-05-13 06:44:01 +04:00
/* CAIF protocol allow maximum 6 link-layers */
for ( i = 0 ; i < 7 ; i + + ) {
phyid = ( dev - > ifindex + i ) & 0x7 ;
if ( phyid = = 0 )
continue ;
if ( cfcnfg_get_phyinfo_rcu ( cnfg , phyid ) = = NULL )
goto got_phyid ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
pr_warn ( " Too many CAIF Link Layers (max 6) \n " ) ;
goto out ;
got_phyid :
phyinfo = kzalloc ( sizeof ( struct cfcnfg_phyinfo ) , GFP_ATOMIC ) ;
2010-03-30 17:56:24 +04:00
switch ( phy_type ) {
case CFPHYTYPE_FRAG :
phy_driver =
2011-05-13 06:44:01 +04:00
cfserl_create ( CFPHYTYPE_FRAG , phyid , stx ) ;
2010-03-30 17:56:24 +04:00
if ( ! phy_driver ) {
2010-09-06 01:31:11 +04:00
pr_warn ( " Out of memory \n " ) ;
2011-05-13 06:44:01 +04:00
goto out ;
2010-03-30 17:56:24 +04:00
}
break ;
case CFPHYTYPE_CAIF :
phy_driver = NULL ;
break ;
default :
2011-05-13 06:44:01 +04:00
goto out ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
phy_layer - > id = phyid ;
phyinfo - > pref = pref ;
phyinfo - > id = phyid ;
phyinfo - > dev_info . id = phyid ;
phyinfo - > dev_info . dev = dev ;
phyinfo - > phy_layer = phy_layer ;
phyinfo - > ifindex = dev - > ifindex ;
phyinfo - > use_stx = stx ;
phyinfo - > use_fcs = fcs ;
2010-06-17 10:55:40 +04:00
2010-03-30 17:56:24 +04:00
phy_layer - > type = phy_type ;
2011-05-13 06:44:01 +04:00
frml = cffrml_create ( phyid , fcs ) ;
2010-03-30 17:56:24 +04:00
if ( ! frml ) {
2010-09-06 01:31:11 +04:00
pr_warn ( " Out of memory \n " ) ;
2011-05-13 06:44:01 +04:00
kfree ( phyinfo ) ;
goto out ;
2010-03-30 17:56:24 +04:00
}
2011-05-13 06:44:01 +04:00
phyinfo - > frm_layer = frml ;
2010-03-30 17:56:24 +04:00
layer_set_up ( frml , cnfg - > mux ) ;
if ( phy_driver ! = NULL ) {
2011-05-13 06:44:01 +04:00
phy_driver - > id = phyid ;
2010-03-30 17:56:24 +04:00
layer_set_dn ( frml , phy_driver ) ;
layer_set_up ( phy_driver , frml ) ;
layer_set_dn ( phy_driver , phy_layer ) ;
layer_set_up ( phy_layer , phy_driver ) ;
} else {
layer_set_dn ( frml , phy_layer ) ;
layer_set_up ( phy_layer , frml ) ;
}
2011-05-13 06:44:01 +04:00
list_add_rcu ( & phyinfo - > node , & cnfg - > phys ) ;
out :
mutex_unlock ( & cnfg - > lock ) ;
2010-03-30 17:56:24 +04:00
}
EXPORT_SYMBOL ( cfcnfg_add_phy_layer ) ;
2011-05-13 06:44:01 +04:00
int cfcnfg_set_phy_state ( struct cfcnfg * cnfg , struct cflayer * phy_layer ,
bool up )
{
struct cfcnfg_phyinfo * phyinfo ;
rcu_read_lock ( ) ;
phyinfo = cfcnfg_get_phyinfo_rcu ( cnfg , phy_layer - > id ) ;
if ( phyinfo = = NULL ) {
rcu_read_unlock ( ) ;
return - ENODEV ;
}
if ( phyinfo - > up = = up ) {
rcu_read_unlock ( ) ;
return 0 ;
}
phyinfo - > up = up ;
if ( up ) {
cffrml_hold ( phyinfo - > frm_layer ) ;
cfmuxl_set_dnlayer ( cnfg - > mux , phyinfo - > frm_layer ,
phy_layer - > id ) ;
} else {
cfmuxl_remove_dnlayer ( cnfg - > mux , phy_layer - > id ) ;
cffrml_put ( phyinfo - > frm_layer ) ;
}
rcu_read_unlock ( ) ;
return 0 ;
}
EXPORT_SYMBOL ( cfcnfg_set_phy_state ) ;
2010-03-30 17:56:24 +04:00
int cfcnfg_del_phy_layer ( struct cfcnfg * cnfg , struct cflayer * phy_layer )
{
struct cflayer * frml , * frml_dn ;
u16 phyid ;
2011-05-13 06:44:01 +04:00
struct cfcnfg_phyinfo * phyinfo ;
might_sleep ( ) ;
mutex_lock ( & cnfg - > lock ) ;
2010-03-30 17:56:24 +04:00
phyid = phy_layer - > id ;
2011-05-13 06:44:01 +04:00
phyinfo = cfcnfg_get_phyinfo_rcu ( cnfg , phyid ) ;
if ( phyinfo = = NULL )
return 0 ;
caif_assert ( phyid = = phyinfo - > id ) ;
caif_assert ( phy_layer = = phyinfo - > phy_layer ) ;
2010-03-30 17:56:24 +04:00
caif_assert ( phy_layer - > id = = phyid ) ;
2011-05-13 06:44:01 +04:00
caif_assert ( phyinfo - > frm_layer - > id = = phyid ) ;
2011-05-13 06:44:02 +04:00
/* Fail if reference count is not zero */
if ( cffrml_refcnt_read ( phyinfo - > frm_layer ) ! = 0 ) {
pr_info ( " Wait for device inuse \n " ) ;
mutex_unlock ( & cnfg - > lock ) ;
return - EAGAIN ;
}
2011-05-13 06:44:01 +04:00
list_del_rcu ( & phyinfo - > node ) ;
synchronize_rcu ( ) ;
2010-03-30 17:56:24 +04:00
2011-05-13 06:44:01 +04:00
frml = phyinfo - > frm_layer ;
2010-03-30 17:56:24 +04:00
frml_dn = frml - > dn ;
cffrml_set_uplayer ( frml , NULL ) ;
cffrml_set_dnlayer ( frml , NULL ) ;
if ( phy_layer ! = frml_dn ) {
layer_set_up ( frml_dn , NULL ) ;
layer_set_dn ( frml_dn , NULL ) ;
}
layer_set_up ( phy_layer , NULL ) ;
2011-05-13 06:44:01 +04:00
if ( phyinfo - > phy_layer ! = frml_dn )
kfree ( frml_dn ) ;
2011-05-13 06:44:02 +04:00
cffrml_free ( frml ) ;
2011-05-13 06:44:01 +04:00
kfree ( phyinfo ) ;
mutex_unlock ( & cnfg - > lock ) ;
2010-03-30 17:56:24 +04:00
return 0 ;
}
EXPORT_SYMBOL ( cfcnfg_del_phy_layer ) ;