2013-11-15 10:50:32 +00:00
/*
* ssi_protocol . c
*
* Implementation of the SSI McSAAB improved protocol .
*
* Copyright ( C ) 2010 Nokia Corporation . All rights reserved .
* Copyright ( C ) 2013 Sebastian Reichel < sre @ kernel . org >
*
* Contact : Carlos Chinea < carlos . chinea @ nokia . com >
*
* 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 .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*/
# include <linux/atomic.h>
# include <linux/clk.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/gpio.h>
# include <linux/if_ether.h>
# include <linux/if_arp.h>
# include <linux/if_phonet.h>
# include <linux/init.h>
# include <linux/irq.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/notifier.h>
# include <linux/scatterlist.h>
# include <linux/skbuff.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/timer.h>
# include <linux/hsi/hsi.h>
# include <linux/hsi/ssi_protocol.h>
void ssi_waketest ( struct hsi_client * cl , unsigned int enable ) ;
# define SSIP_TXQUEUE_LEN 100
# define SSIP_MAX_MTU 65535
# define SSIP_DEFAULT_MTU 4000
# define PN_MEDIA_SOS 21
# define SSIP_MIN_PN_HDR 6 /* FIXME: Revisit */
# define SSIP_WDTOUT 2000 /* FIXME: has to be 500 msecs */
# define SSIP_KATOUT 15 /* 15 msecs */
# define SSIP_MAX_CMDS 5 /* Number of pre-allocated commands buffers */
# define SSIP_BYTES_TO_FRAMES(x) ((((x) - 1) >> 2) + 1)
# define SSIP_CMT_LOADER_SYNC 0x11223344
/*
* SSI protocol command definitions
*/
# define SSIP_COMMAND(data) ((data) >> 28)
# define SSIP_PAYLOAD(data) ((data) & 0xfffffff)
/* Commands */
# define SSIP_SW_BREAK 0
# define SSIP_BOOTINFO_REQ 1
# define SSIP_BOOTINFO_RESP 2
# define SSIP_WAKETEST_RESULT 3
# define SSIP_START_TRANS 4
# define SSIP_READY 5
/* Payloads */
# define SSIP_DATA_VERSION(data) ((data) & 0xff)
# define SSIP_LOCAL_VERID 1
# define SSIP_WAKETEST_OK 0
# define SSIP_WAKETEST_FAILED 1
# define SSIP_PDU_LENGTH(data) (((data) >> 8) & 0xffff)
# define SSIP_MSG_ID(data) ((data) & 0xff)
/* Generic Command */
# define SSIP_CMD(cmd, payload) (((cmd) << 28) | ((payload) & 0xfffffff))
/* Commands for the control channel */
# define SSIP_BOOTINFO_REQ_CMD(ver) \
SSIP_CMD ( SSIP_BOOTINFO_REQ , SSIP_DATA_VERSION ( ver ) )
# define SSIP_BOOTINFO_RESP_CMD(ver) \
SSIP_CMD ( SSIP_BOOTINFO_RESP , SSIP_DATA_VERSION ( ver ) )
# define SSIP_START_TRANS_CMD(pdulen, id) \
SSIP_CMD ( SSIP_START_TRANS , ( ( ( pdulen ) < < 8 ) | SSIP_MSG_ID ( id ) ) )
# define SSIP_READY_CMD SSIP_CMD(SSIP_READY, 0)
# define SSIP_SWBREAK_CMD SSIP_CMD(SSIP_SW_BREAK, 0)
2016-06-18 00:55:22 +02:00
# define SSIP_WAKETEST_FLAG 0
2013-11-15 10:50:32 +00:00
/* Main state machine states */
enum {
INIT ,
HANDSHAKE ,
ACTIVE ,
} ;
/* Send state machine states */
enum {
SEND_IDLE ,
WAIT4READY ,
SEND_READY ,
SENDING ,
SENDING_SWBREAK ,
} ;
/* Receive state machine states */
enum {
RECV_IDLE ,
RECV_READY ,
RECEIVING ,
} ;
/**
* struct ssi_protocol - SSI protocol ( McSAAB ) data
* @ main_state : Main state machine
* @ send_state : TX state machine
* @ recv_state : RX state machine
2016-06-18 00:55:22 +02:00
* @ flags : Flags , currently only used to follow wake line test
2013-11-15 10:50:32 +00:00
* @ rxid : RX data id
* @ txid : TX data id
* @ txqueue_len : TX queue length
* @ tx_wd : TX watchdog
* @ rx_wd : RX watchdog
* @ keep_alive : Workaround for SSI HW bug
* @ lock : To serialize access to this struct
* @ netdev : Phonet network device
* @ txqueue : TX data queue
* @ cmdqueue : Queue of free commands
* @ cl : HSI client own reference
* @ link : Link for ssip_list
* @ tx_usecount : Refcount to keep track the slaves that use the wake line
* @ channel_id_cmd : HSI channel id for command stream
* @ channel_id_data : HSI channel id for data stream
*/
struct ssi_protocol {
unsigned int main_state ;
unsigned int send_state ;
unsigned int recv_state ;
2016-06-18 00:55:22 +02:00
unsigned long flags ;
2013-11-15 10:50:32 +00:00
u8 rxid ;
u8 txid ;
unsigned int txqueue_len ;
struct timer_list tx_wd ;
struct timer_list rx_wd ;
struct timer_list keep_alive ; /* wake-up workaround */
spinlock_t lock ;
struct net_device * netdev ;
struct list_head txqueue ;
struct list_head cmdqueue ;
2016-06-18 00:58:39 +02:00
struct work_struct work ;
2013-11-15 10:50:32 +00:00
struct hsi_client * cl ;
struct list_head link ;
atomic_t tx_usecnt ;
int channel_id_cmd ;
int channel_id_data ;
} ;
/* List of ssi protocol instances */
static LIST_HEAD ( ssip_list ) ;
static void ssip_rxcmd_complete ( struct hsi_msg * msg ) ;
static inline void ssip_set_cmd ( struct hsi_msg * msg , u32 cmd )
{
u32 * data ;
data = sg_virt ( msg - > sgt . sgl ) ;
* data = cmd ;
}
static inline u32 ssip_get_cmd ( struct hsi_msg * msg )
{
u32 * data ;
data = sg_virt ( msg - > sgt . sgl ) ;
return * data ;
}
static void ssip_skb_to_msg ( struct sk_buff * skb , struct hsi_msg * msg )
{
skb_frag_t * frag ;
struct scatterlist * sg ;
int i ;
BUG_ON ( msg - > sgt . nents ! = ( unsigned int ) ( skb_shinfo ( skb ) - > nr_frags + 1 ) ) ;
sg = msg - > sgt . sgl ;
sg_set_buf ( sg , skb - > data , skb_headlen ( skb ) ) ;
for ( i = 0 ; i < skb_shinfo ( skb ) - > nr_frags ; i + + ) {
sg = sg_next ( sg ) ;
BUG_ON ( ! sg ) ;
frag = & skb_shinfo ( skb ) - > frags [ i ] ;
sg_set_page ( sg , frag - > page . p , frag - > size , frag - > page_offset ) ;
}
}
static void ssip_free_data ( struct hsi_msg * msg )
{
struct sk_buff * skb ;
skb = msg - > context ;
pr_debug ( " free data: msg %p context %p skb %p \n " , msg , msg - > context ,
skb ) ;
msg - > destructor = NULL ;
dev_kfree_skb ( skb ) ;
hsi_free_msg ( msg ) ;
}
static struct hsi_msg * ssip_alloc_data ( struct ssi_protocol * ssi ,
struct sk_buff * skb , gfp_t flags )
{
struct hsi_msg * msg ;
msg = hsi_alloc_msg ( skb_shinfo ( skb ) - > nr_frags + 1 , flags ) ;
if ( ! msg )
return NULL ;
ssip_skb_to_msg ( skb , msg ) ;
msg - > destructor = ssip_free_data ;
msg - > channel = ssi - > channel_id_data ;
msg - > context = skb ;
return msg ;
}
static inline void ssip_release_cmd ( struct hsi_msg * msg )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( msg - > cl ) ;
dev_dbg ( & msg - > cl - > device , " Release cmd 0x%08x \n " , ssip_get_cmd ( msg ) ) ;
spin_lock_bh ( & ssi - > lock ) ;
list_add_tail ( & msg - > link , & ssi - > cmdqueue ) ;
spin_unlock_bh ( & ssi - > lock ) ;
}
static struct hsi_msg * ssip_claim_cmd ( struct ssi_protocol * ssi )
{
struct hsi_msg * msg ;
BUG_ON ( list_empty ( & ssi - > cmdqueue ) ) ;
spin_lock_bh ( & ssi - > lock ) ;
msg = list_first_entry ( & ssi - > cmdqueue , struct hsi_msg , link ) ;
list_del ( & msg - > link ) ;
spin_unlock_bh ( & ssi - > lock ) ;
msg - > destructor = ssip_release_cmd ;
return msg ;
}
static void ssip_free_cmds ( struct ssi_protocol * ssi )
{
struct hsi_msg * msg , * tmp ;
list_for_each_entry_safe ( msg , tmp , & ssi - > cmdqueue , link ) {
list_del ( & msg - > link ) ;
msg - > destructor = NULL ;
kfree ( sg_virt ( msg - > sgt . sgl ) ) ;
hsi_free_msg ( msg ) ;
}
}
static int ssip_alloc_cmds ( struct ssi_protocol * ssi )
{
struct hsi_msg * msg ;
u32 * buf ;
unsigned int i ;
for ( i = 0 ; i < SSIP_MAX_CMDS ; i + + ) {
msg = hsi_alloc_msg ( 1 , GFP_KERNEL ) ;
if ( ! msg )
goto out ;
buf = kmalloc ( sizeof ( * buf ) , GFP_KERNEL ) ;
if ( ! buf ) {
hsi_free_msg ( msg ) ;
goto out ;
}
sg_init_one ( msg - > sgt . sgl , buf , sizeof ( * buf ) ) ;
msg - > channel = ssi - > channel_id_cmd ;
list_add_tail ( & msg - > link , & ssi - > cmdqueue ) ;
}
return 0 ;
out :
ssip_free_cmds ( ssi ) ;
return - ENOMEM ;
}
static void ssip_set_rxstate ( struct ssi_protocol * ssi , unsigned int state )
{
ssi - > recv_state = state ;
switch ( state ) {
case RECV_IDLE :
del_timer ( & ssi - > rx_wd ) ;
if ( ssi - > send_state = = SEND_IDLE )
del_timer ( & ssi - > keep_alive ) ;
break ;
case RECV_READY :
/* CMT speech workaround */
if ( atomic_read ( & ssi - > tx_usecnt ) )
break ;
/* Otherwise fall through */
case RECEIVING :
mod_timer ( & ssi - > keep_alive , jiffies +
msecs_to_jiffies ( SSIP_KATOUT ) ) ;
mod_timer ( & ssi - > rx_wd , jiffies + msecs_to_jiffies ( SSIP_WDTOUT ) ) ;
break ;
default :
break ;
}
}
static void ssip_set_txstate ( struct ssi_protocol * ssi , unsigned int state )
{
ssi - > send_state = state ;
switch ( state ) {
case SEND_IDLE :
case SEND_READY :
del_timer ( & ssi - > tx_wd ) ;
if ( ssi - > recv_state = = RECV_IDLE )
del_timer ( & ssi - > keep_alive ) ;
break ;
case WAIT4READY :
case SENDING :
case SENDING_SWBREAK :
mod_timer ( & ssi - > keep_alive ,
jiffies + msecs_to_jiffies ( SSIP_KATOUT ) ) ;
mod_timer ( & ssi - > tx_wd , jiffies + msecs_to_jiffies ( SSIP_WDTOUT ) ) ;
break ;
default :
break ;
}
}
struct hsi_client * ssip_slave_get_master ( struct hsi_client * slave )
{
struct hsi_client * master = ERR_PTR ( - ENODEV ) ;
struct ssi_protocol * ssi ;
list_for_each_entry ( ssi , & ssip_list , link )
if ( slave - > device . parent = = ssi - > cl - > device . parent ) {
master = ssi - > cl ;
break ;
}
return master ;
}
EXPORT_SYMBOL_GPL ( ssip_slave_get_master ) ;
int ssip_slave_start_tx ( struct hsi_client * master )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( master ) ;
dev_dbg ( & master - > device , " start TX %d \n " , atomic_read ( & ssi - > tx_usecnt ) ) ;
spin_lock_bh ( & ssi - > lock ) ;
if ( ssi - > send_state = = SEND_IDLE ) {
ssip_set_txstate ( ssi , WAIT4READY ) ;
hsi_start_tx ( master ) ;
}
spin_unlock_bh ( & ssi - > lock ) ;
atomic_inc ( & ssi - > tx_usecnt ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ssip_slave_start_tx ) ;
int ssip_slave_stop_tx ( struct hsi_client * master )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( master ) ;
WARN_ON_ONCE ( atomic_read ( & ssi - > tx_usecnt ) = = 0 ) ;
if ( atomic_dec_and_test ( & ssi - > tx_usecnt ) ) {
spin_lock_bh ( & ssi - > lock ) ;
if ( ( ssi - > send_state = = SEND_READY ) | |
( ssi - > send_state = = WAIT4READY ) ) {
ssip_set_txstate ( ssi , SEND_IDLE ) ;
hsi_stop_tx ( master ) ;
}
spin_unlock_bh ( & ssi - > lock ) ;
}
dev_dbg ( & master - > device , " stop TX %d \n " , atomic_read ( & ssi - > tx_usecnt ) ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ssip_slave_stop_tx ) ;
int ssip_slave_running ( struct hsi_client * master )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( master ) ;
return netif_running ( ssi - > netdev ) ;
}
EXPORT_SYMBOL_GPL ( ssip_slave_running ) ;
static void ssip_reset ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct list_head * head , * tmp ;
struct hsi_msg * msg ;
if ( netif_running ( ssi - > netdev ) )
netif_carrier_off ( ssi - > netdev ) ;
hsi_flush ( cl ) ;
spin_lock_bh ( & ssi - > lock ) ;
if ( ssi - > send_state ! = SEND_IDLE )
hsi_stop_tx ( cl ) ;
2016-06-18 00:55:22 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
if ( test_and_clear_bit ( SSIP_WAKETEST_FLAG , & ssi - > flags ) )
ssi_waketest ( cl , 0 ) ; /* FIXME: To be removed */
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
del_timer ( & ssi - > rx_wd ) ;
del_timer ( & ssi - > tx_wd ) ;
del_timer ( & ssi - > keep_alive ) ;
ssi - > main_state = 0 ;
ssi - > send_state = 0 ;
ssi - > recv_state = 0 ;
2016-06-18 00:55:22 +02:00
ssi - > flags = 0 ;
2013-11-15 10:50:32 +00:00
ssi - > rxid = 0 ;
ssi - > txid = 0 ;
list_for_each_safe ( head , tmp , & ssi - > txqueue ) {
msg = list_entry ( head , struct hsi_msg , link ) ;
dev_dbg ( & cl - > device , " Pending TX data \n " ) ;
list_del ( head ) ;
ssip_free_data ( msg ) ;
}
ssi - > txqueue_len = 0 ;
spin_unlock_bh ( & ssi - > lock ) ;
}
static void ssip_dump_state ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
spin_lock_bh ( & ssi - > lock ) ;
dev_err ( & cl - > device , " Main state: %d \n " , ssi - > main_state ) ;
dev_err ( & cl - > device , " Recv state: %d \n " , ssi - > recv_state ) ;
dev_err ( & cl - > device , " Send state: %d \n " , ssi - > send_state ) ;
dev_err ( & cl - > device , " CMT %s \n " , ( ssi - > main_state = = ACTIVE ) ?
" Online " : " Offline " ) ;
2016-06-18 00:55:22 +02:00
dev_err ( & cl - > device , " Wake test %d \n " ,
test_bit ( SSIP_WAKETEST_FLAG , & ssi - > flags ) ) ;
2013-11-15 10:50:32 +00:00
dev_err ( & cl - > device , " Data RX id: %d \n " , ssi - > rxid ) ;
dev_err ( & cl - > device , " Data TX id: %d \n " , ssi - > txid ) ;
list_for_each_entry ( msg , & ssi - > txqueue , link )
dev_err ( & cl - > device , " pending TX data (%p) \n " , msg ) ;
spin_unlock_bh ( & ssi - > lock ) ;
}
static void ssip_error ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
ssip_dump_state ( cl ) ;
ssip_reset ( cl ) ;
msg = ssip_claim_cmd ( ssi ) ;
msg - > complete = ssip_rxcmd_complete ;
hsi_async_read ( cl , msg ) ;
}
2017-10-04 16:26:59 -07:00
static void ssip_keep_alive ( struct timer_list * t )
2013-11-15 10:50:32 +00:00
{
2017-10-04 16:26:59 -07:00
struct ssi_protocol * ssi = from_timer ( ssi , t , keep_alive ) ;
struct hsi_client * cl = ssi - > cl ;
2013-11-15 10:50:32 +00:00
dev_dbg ( & cl - > device , " Keep alive kick in: m(%d) r(%d) s(%d) \n " ,
ssi - > main_state , ssi - > recv_state , ssi - > send_state ) ;
spin_lock ( & ssi - > lock ) ;
if ( ssi - > recv_state = = RECV_IDLE )
switch ( ssi - > send_state ) {
case SEND_READY :
if ( atomic_read ( & ssi - > tx_usecnt ) = = 0 )
break ;
/*
* Fall through . Workaround for cmt - speech
* in that case we relay on audio timers .
*/
case SEND_IDLE :
spin_unlock ( & ssi - > lock ) ;
return ;
}
mod_timer ( & ssi - > keep_alive , jiffies + msecs_to_jiffies ( SSIP_KATOUT ) ) ;
spin_unlock ( & ssi - > lock ) ;
}
2017-10-04 16:26:59 -07:00
static void ssip_rx_wd ( struct timer_list * t )
{
struct ssi_protocol * ssi = from_timer ( ssi , t , rx_wd ) ;
struct hsi_client * cl = ssi - > cl ;
dev_err ( & cl - > device , " Watchdog trigerred \n " ) ;
ssip_error ( cl ) ;
}
2017-10-05 10:10:35 -07:00
static void ssip_tx_wd ( struct timer_list * t )
2013-11-15 10:50:32 +00:00
{
2017-10-04 16:26:59 -07:00
struct ssi_protocol * ssi = from_timer ( ssi , t , tx_wd ) ;
struct hsi_client * cl = ssi - > cl ;
2013-11-15 10:50:32 +00:00
dev_err ( & cl - > device , " Watchdog trigerred \n " ) ;
ssip_error ( cl ) ;
}
static void ssip_send_bootinfo_req_cmd ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
dev_dbg ( & cl - > device , " Issuing BOOT INFO REQ command \n " ) ;
msg = ssip_claim_cmd ( ssi ) ;
ssip_set_cmd ( msg , SSIP_BOOTINFO_REQ_CMD ( SSIP_LOCAL_VERID ) ) ;
msg - > complete = ssip_release_cmd ;
hsi_async_write ( cl , msg ) ;
dev_dbg ( & cl - > device , " Issuing RX command \n " ) ;
msg = ssip_claim_cmd ( ssi ) ;
msg - > complete = ssip_rxcmd_complete ;
hsi_async_read ( cl , msg ) ;
}
static void ssip_start_rx ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
dev_dbg ( & cl - > device , " RX start M(%d) R(%d) \n " , ssi - > main_state ,
ssi - > recv_state ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
/*
* We can have two UP events in a row due to a short low
* high transition . Therefore we need to ignore the sencond UP event .
*/
if ( ( ssi - > main_state ! = ACTIVE ) | | ( ssi - > recv_state = = RECV_READY ) ) {
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
return ;
}
ssip_set_rxstate ( ssi , RECV_READY ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
msg = ssip_claim_cmd ( ssi ) ;
ssip_set_cmd ( msg , SSIP_READY_CMD ) ;
msg - > complete = ssip_release_cmd ;
dev_dbg ( & cl - > device , " Send READY \n " ) ;
hsi_async_write ( cl , msg ) ;
}
static void ssip_stop_rx ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
dev_dbg ( & cl - > device , " RX stop M(%d) \n " , ssi - > main_state ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( likely ( ssi - > main_state = = ACTIVE ) )
ssip_set_rxstate ( ssi , RECV_IDLE ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
}
static void ssip_free_strans ( struct hsi_msg * msg )
{
ssip_free_data ( msg - > context ) ;
ssip_release_cmd ( msg ) ;
}
static void ssip_strans_complete ( struct hsi_msg * msg )
{
struct hsi_client * cl = msg - > cl ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * data ;
data = msg - > context ;
ssip_release_cmd ( msg ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssip_set_txstate ( ssi , SENDING ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
hsi_async_write ( cl , data ) ;
}
static int ssip_xmit ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg , * dmsg ;
struct sk_buff * skb ;
spin_lock_bh ( & ssi - > lock ) ;
if ( list_empty ( & ssi - > txqueue ) ) {
spin_unlock_bh ( & ssi - > lock ) ;
return 0 ;
}
dmsg = list_first_entry ( & ssi - > txqueue , struct hsi_msg , link ) ;
list_del ( & dmsg - > link ) ;
ssi - > txqueue_len - - ;
spin_unlock_bh ( & ssi - > lock ) ;
msg = ssip_claim_cmd ( ssi ) ;
skb = dmsg - > context ;
msg - > context = dmsg ;
msg - > complete = ssip_strans_complete ;
msg - > destructor = ssip_free_strans ;
spin_lock_bh ( & ssi - > lock ) ;
ssip_set_cmd ( msg , SSIP_START_TRANS_CMD ( SSIP_BYTES_TO_FRAMES ( skb - > len ) ,
ssi - > txid ) ) ;
ssi - > txid + + ;
ssip_set_txstate ( ssi , SENDING ) ;
spin_unlock_bh ( & ssi - > lock ) ;
dev_dbg ( & cl - > device , " Send STRANS (%d frames) \n " ,
SSIP_BYTES_TO_FRAMES ( skb - > len ) ) ;
return hsi_async_write ( cl , msg ) ;
}
/* In soft IRQ context */
static void ssip_pn_rx ( struct sk_buff * skb )
{
struct net_device * dev = skb - > dev ;
if ( unlikely ( ! netif_running ( dev ) ) ) {
dev_dbg ( & dev - > dev , " Drop RX packet \n " ) ;
dev - > stats . rx_dropped + + ;
dev_kfree_skb ( skb ) ;
return ;
}
if ( unlikely ( ! pskb_may_pull ( skb , SSIP_MIN_PN_HDR ) ) ) {
dev_dbg ( & dev - > dev , " Error drop RX packet \n " ) ;
dev - > stats . rx_errors + + ;
dev - > stats . rx_length_errors + + ;
dev_kfree_skb ( skb ) ;
return ;
}
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = skb - > len ;
/* length field is exchanged in network byte order */
( ( u16 * ) skb - > data ) [ 2 ] = ntohs ( ( ( u16 * ) skb - > data ) [ 2 ] ) ;
dev_dbg ( & dev - > dev , " RX length fixed (%04x -> %u) \n " ,
( ( u16 * ) skb - > data ) [ 2 ] , ntohs ( ( ( u16 * ) skb - > data ) [ 2 ] ) ) ;
skb - > protocol = htons ( ETH_P_PHONET ) ;
skb_reset_mac_header ( skb ) ;
__skb_pull ( skb , 1 ) ;
netif_rx ( skb ) ;
}
static void ssip_rx_data_complete ( struct hsi_msg * msg )
{
struct hsi_client * cl = msg - > cl ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct sk_buff * skb ;
if ( msg - > status = = HSI_STATUS_ERROR ) {
dev_err ( & cl - > device , " RX data error \n " ) ;
ssip_free_data ( msg ) ;
ssip_error ( cl ) ;
return ;
}
del_timer ( & ssi - > rx_wd ) ; /* FIXME: Revisit */
skb = msg - > context ;
ssip_pn_rx ( skb ) ;
hsi_free_msg ( msg ) ;
}
static void ssip_rx_bootinforeq ( struct hsi_client * cl , u32 cmd )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
/* Workaroud: Ignore CMT Loader message leftover */
if ( cmd = = SSIP_CMT_LOADER_SYNC )
return ;
switch ( ssi - > main_state ) {
case ACTIVE :
dev_err ( & cl - > device , " Boot info req on active state \n " ) ;
ssip_error ( cl ) ;
/* Fall through */
case INIT :
2016-01-17 16:49:08 +01:00
case HANDSHAKE :
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssi - > main_state = HANDSHAKE ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2016-06-18 00:55:22 +02:00
if ( ! test_and_set_bit ( SSIP_WAKETEST_FLAG , & ssi - > flags ) )
2013-11-15 10:50:32 +00:00
ssi_waketest ( cl , 1 ) ; /* FIXME: To be removed */
2016-06-18 00:55:22 +02:00
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
/* Start boot handshake watchdog */
mod_timer ( & ssi - > tx_wd , jiffies + msecs_to_jiffies ( SSIP_WDTOUT ) ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
dev_dbg ( & cl - > device , " Send BOOTINFO_RESP \n " ) ;
if ( SSIP_DATA_VERSION ( cmd ) ! = SSIP_LOCAL_VERID )
dev_warn ( & cl - > device , " boot info req verid mismatch \n " ) ;
msg = ssip_claim_cmd ( ssi ) ;
ssip_set_cmd ( msg , SSIP_BOOTINFO_RESP_CMD ( SSIP_LOCAL_VERID ) ) ;
msg - > complete = ssip_release_cmd ;
hsi_async_write ( cl , msg ) ;
break ;
default :
dev_dbg ( & cl - > device , " Wrong state M(%d) \n " , ssi - > main_state ) ;
break ;
}
}
static void ssip_rx_bootinforesp ( struct hsi_client * cl , u32 cmd )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
if ( SSIP_DATA_VERSION ( cmd ) ! = SSIP_LOCAL_VERID )
dev_warn ( & cl - > device , " boot info resp verid mismatch \n " ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( ssi - > main_state ! = ACTIVE )
/* Use tx_wd as a boot watchdog in non ACTIVE state */
mod_timer ( & ssi - > tx_wd , jiffies + msecs_to_jiffies ( SSIP_WDTOUT ) ) ;
else
dev_dbg ( & cl - > device , " boot info resp ignored M(%d) \n " ,
ssi - > main_state ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
}
static void ssip_rx_waketest ( struct hsi_client * cl , u32 cmd )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
unsigned int wkres = SSIP_PAYLOAD ( cmd ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( ssi - > main_state ! = HANDSHAKE ) {
dev_dbg ( & cl - > device , " wake lines test ignored M(%d) \n " ,
ssi - > main_state ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
return ;
}
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2016-06-18 00:55:22 +02:00
if ( test_and_clear_bit ( SSIP_WAKETEST_FLAG , & ssi - > flags ) )
2013-11-15 10:50:32 +00:00
ssi_waketest ( cl , 0 ) ; /* FIXME: To be removed */
2016-06-18 00:55:22 +02:00
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssi - > main_state = ACTIVE ;
del_timer ( & ssi - > tx_wd ) ; /* Stop boot handshake timer */
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
dev_notice ( & cl - > device , " WAKELINES TEST %s \n " ,
wkres & SSIP_WAKETEST_FAILED ? " FAILED " : " OK " ) ;
if ( wkres & SSIP_WAKETEST_FAILED ) {
ssip_error ( cl ) ;
return ;
}
dev_dbg ( & cl - > device , " CMT is ONLINE \n " ) ;
netif_wake_queue ( ssi - > netdev ) ;
netif_carrier_on ( ssi - > netdev ) ;
}
static void ssip_rx_ready ( struct hsi_client * cl )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( unlikely ( ssi - > main_state ! = ACTIVE ) ) {
dev_dbg ( & cl - > device , " READY on wrong state: S(%d) M(%d) \n " ,
ssi - > send_state , ssi - > main_state ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
return ;
}
if ( ssi - > send_state ! = WAIT4READY ) {
dev_dbg ( & cl - > device , " Ignore spurious READY command \n " ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
return ;
}
ssip_set_txstate ( ssi , SEND_READY ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssip_xmit ( cl ) ;
}
static void ssip_rx_strans ( struct hsi_client * cl , u32 cmd )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct sk_buff * skb ;
struct hsi_msg * msg ;
int len = SSIP_PDU_LENGTH ( cmd ) ;
dev_dbg ( & cl - > device , " RX strans: %d frames \n " , len ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( unlikely ( ssi - > main_state ! = ACTIVE ) ) {
dev_err ( & cl - > device , " START TRANS wrong state: S(%d) M(%d) \n " ,
ssi - > send_state , ssi - > main_state ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
return ;
}
ssip_set_rxstate ( ssi , RECEIVING ) ;
if ( unlikely ( SSIP_MSG_ID ( cmd ) ! = ssi - > rxid ) ) {
2015-08-12 16:15:35 +02:00
dev_err ( & cl - > device , " START TRANS id %d expected %d \n " ,
2013-11-15 10:50:32 +00:00
SSIP_MSG_ID ( cmd ) , ssi - > rxid ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
goto out1 ;
}
ssi - > rxid + + ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
skb = netdev_alloc_skb ( ssi - > netdev , len * 4 ) ;
if ( unlikely ( ! skb ) ) {
dev_err ( & cl - > device , " No memory for rx skb \n " ) ;
goto out1 ;
}
skb - > dev = ssi - > netdev ;
skb_put ( skb , len * 4 ) ;
msg = ssip_alloc_data ( ssi , skb , GFP_ATOMIC ) ;
if ( unlikely ( ! msg ) ) {
dev_err ( & cl - > device , " No memory for RX data msg \n " ) ;
goto out2 ;
}
msg - > complete = ssip_rx_data_complete ;
hsi_async_read ( cl , msg ) ;
return ;
out2 :
dev_kfree_skb ( skb ) ;
out1 :
ssip_error ( cl ) ;
}
static void ssip_rxcmd_complete ( struct hsi_msg * msg )
{
struct hsi_client * cl = msg - > cl ;
u32 cmd = ssip_get_cmd ( msg ) ;
unsigned int cmdid = SSIP_COMMAND ( cmd ) ;
if ( msg - > status = = HSI_STATUS_ERROR ) {
dev_err ( & cl - > device , " RX error detected \n " ) ;
ssip_release_cmd ( msg ) ;
ssip_error ( cl ) ;
return ;
}
hsi_async_read ( cl , msg ) ;
dev_dbg ( & cl - > device , " RX cmd: 0x%08x \n " , cmd ) ;
switch ( cmdid ) {
case SSIP_SW_BREAK :
/* Ignored */
break ;
case SSIP_BOOTINFO_REQ :
ssip_rx_bootinforeq ( cl , cmd ) ;
break ;
case SSIP_BOOTINFO_RESP :
ssip_rx_bootinforesp ( cl , cmd ) ;
break ;
case SSIP_WAKETEST_RESULT :
ssip_rx_waketest ( cl , cmd ) ;
break ;
case SSIP_START_TRANS :
ssip_rx_strans ( cl , cmd ) ;
break ;
case SSIP_READY :
ssip_rx_ready ( cl ) ;
break ;
default :
dev_warn ( & cl - > device , " command 0x%08x not supported \n " , cmd ) ;
break ;
}
}
static void ssip_swbreak_complete ( struct hsi_msg * msg )
{
struct hsi_client * cl = msg - > cl ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
ssip_release_cmd ( msg ) ;
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( list_empty ( & ssi - > txqueue ) ) {
if ( atomic_read ( & ssi - > tx_usecnt ) ) {
ssip_set_txstate ( ssi , SEND_READY ) ;
} else {
ssip_set_txstate ( ssi , SEND_IDLE ) ;
hsi_stop_tx ( cl ) ;
}
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
} else {
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssip_xmit ( cl ) ;
}
netif_wake_queue ( ssi - > netdev ) ;
}
static void ssip_tx_data_complete ( struct hsi_msg * msg )
{
struct hsi_client * cl = msg - > cl ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * cmsg ;
if ( msg - > status = = HSI_STATUS_ERROR ) {
dev_err ( & cl - > device , " TX data error \n " ) ;
ssip_error ( cl ) ;
goto out ;
}
2016-06-18 00:57:20 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
if ( list_empty ( & ssi - > txqueue ) ) {
ssip_set_txstate ( ssi , SENDING_SWBREAK ) ;
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
cmsg = ssip_claim_cmd ( ssi ) ;
ssip_set_cmd ( cmsg , SSIP_SWBREAK_CMD ) ;
cmsg - > complete = ssip_swbreak_complete ;
dev_dbg ( & cl - > device , " Send SWBREAK \n " ) ;
hsi_async_write ( cl , cmsg ) ;
} else {
2016-06-18 00:57:20 +02:00
spin_unlock_bh ( & ssi - > lock ) ;
2013-11-15 10:50:32 +00:00
ssip_xmit ( cl ) ;
}
out :
ssip_free_data ( msg ) ;
}
2014-07-20 13:17:20 +08:00
static void ssip_port_event ( struct hsi_client * cl , unsigned long event )
2013-11-15 10:50:32 +00:00
{
switch ( event ) {
case HSI_EVENT_START_RX :
ssip_start_rx ( cl ) ;
break ;
case HSI_EVENT_STOP_RX :
ssip_stop_rx ( cl ) ;
break ;
default :
return ;
}
}
static int ssip_pn_open ( struct net_device * dev )
{
struct hsi_client * cl = to_hsi_client ( dev - > dev . parent ) ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
int err ;
err = hsi_claim_port ( cl , 1 ) ;
if ( err < 0 ) {
dev_err ( & cl - > device , " SSI port already claimed \n " ) ;
return err ;
}
err = hsi_register_port_event ( cl , ssip_port_event ) ;
if ( err < 0 ) {
dev_err ( & cl - > device , " Register HSI port event failed (%d) \n " ,
err ) ;
return err ;
}
dev_dbg ( & cl - > device , " Configuring SSI port \n " ) ;
hsi_setup ( cl ) ;
2016-06-18 00:55:22 +02:00
if ( ! test_and_set_bit ( SSIP_WAKETEST_FLAG , & ssi - > flags ) )
2013-11-15 10:50:32 +00:00
ssi_waketest ( cl , 1 ) ; /* FIXME: To be removed */
2016-06-18 00:55:22 +02:00
spin_lock_bh ( & ssi - > lock ) ;
2016-01-17 16:49:08 +01:00
ssi - > main_state = HANDSHAKE ;
2013-11-15 10:50:32 +00:00
spin_unlock_bh ( & ssi - > lock ) ;
2016-01-17 16:49:08 +01:00
ssip_send_bootinfo_req_cmd ( cl ) ;
2013-11-15 10:50:32 +00:00
return 0 ;
}
static int ssip_pn_stop ( struct net_device * dev )
{
struct hsi_client * cl = to_hsi_client ( dev - > dev . parent ) ;
ssip_reset ( cl ) ;
hsi_unregister_port_event ( cl ) ;
hsi_release_port ( cl ) ;
return 0 ;
}
2016-06-18 00:58:39 +02:00
static void ssip_xmit_work ( struct work_struct * work )
{
struct ssi_protocol * ssi =
container_of ( work , struct ssi_protocol , work ) ;
struct hsi_client * cl = ssi - > cl ;
ssip_xmit ( cl ) ;
}
2013-11-15 10:50:32 +00:00
static int ssip_pn_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct hsi_client * cl = to_hsi_client ( dev - > dev . parent ) ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
struct hsi_msg * msg ;
if ( ( skb - > protocol ! = htons ( ETH_P_PHONET ) ) | |
( skb - > len < SSIP_MIN_PN_HDR ) )
goto drop ;
/* Pad to 32-bits - FIXME: Revisit*/
if ( ( skb - > len & 3 ) & & skb_pad ( skb , 4 - ( skb - > len & 3 ) ) )
2017-04-21 13:39:09 +03:00
goto inc_dropped ;
2013-11-15 10:50:32 +00:00
/*
* Modem sends Phonet messages over SSI with its own endianess . . .
* Assume that modem has the same endianess as we do .
*/
if ( skb_cow_head ( skb , 0 ) )
goto drop ;
/* length field is exchanged in network byte order */
( ( u16 * ) skb - > data ) [ 2 ] = htons ( ( ( u16 * ) skb - > data ) [ 2 ] ) ;
msg = ssip_alloc_data ( ssi , skb , GFP_ATOMIC ) ;
if ( ! msg ) {
dev_dbg ( & cl - > device , " Dropping tx data: No memory \n " ) ;
goto drop ;
}
msg - > complete = ssip_tx_data_complete ;
spin_lock_bh ( & ssi - > lock ) ;
if ( unlikely ( ssi - > main_state ! = ACTIVE ) ) {
spin_unlock_bh ( & ssi - > lock ) ;
dev_dbg ( & cl - > device , " Dropping tx data: CMT is OFFLINE \n " ) ;
goto drop2 ;
}
list_add_tail ( & msg - > link , & ssi - > txqueue ) ;
ssi - > txqueue_len + + ;
if ( dev - > tx_queue_len < ssi - > txqueue_len ) {
dev_info ( & cl - > device , " TX queue full %d \n " , ssi - > txqueue_len ) ;
netif_stop_queue ( dev ) ;
}
if ( ssi - > send_state = = SEND_IDLE ) {
ssip_set_txstate ( ssi , WAIT4READY ) ;
spin_unlock_bh ( & ssi - > lock ) ;
dev_dbg ( & cl - > device , " Start TX qlen %d \n " , ssi - > txqueue_len ) ;
hsi_start_tx ( cl ) ;
} else if ( ssi - > send_state = = SEND_READY ) {
/* Needed for cmt-speech workaround */
dev_dbg ( & cl - > device , " Start TX on SEND READY qlen %d \n " ,
ssi - > txqueue_len ) ;
spin_unlock_bh ( & ssi - > lock ) ;
2016-06-18 00:58:39 +02:00
schedule_work ( & ssi - > work ) ;
2013-11-15 10:50:32 +00:00
} else {
spin_unlock_bh ( & ssi - > lock ) ;
}
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
return 0 ;
drop2 :
hsi_free_msg ( msg ) ;
drop :
dev_kfree_skb ( skb ) ;
2017-04-21 13:39:09 +03:00
inc_dropped :
dev - > stats . tx_dropped + + ;
2013-11-15 10:50:32 +00:00
return 0 ;
}
/* CMT reset event handler */
void ssip_reset_event ( struct hsi_client * master )
{
struct ssi_protocol * ssi = hsi_client_drvdata ( master ) ;
dev_err ( & ssi - > cl - > device , " CMT reset detected! \n " ) ;
ssip_error ( ssi - > cl ) ;
}
EXPORT_SYMBOL_GPL ( ssip_reset_event ) ;
static const struct net_device_ops ssip_pn_ops = {
. ndo_open = ssip_pn_open ,
. ndo_stop = ssip_pn_stop ,
. ndo_start_xmit = ssip_pn_xmit ,
} ;
static void ssip_pn_setup ( struct net_device * dev )
{
dev - > features = 0 ;
dev - > netdev_ops = & ssip_pn_ops ;
dev - > type = ARPHRD_PHONET ;
dev - > flags = IFF_POINTOPOINT | IFF_NOARP ;
dev - > mtu = SSIP_DEFAULT_MTU ;
dev - > hard_header_len = 1 ;
dev - > dev_addr [ 0 ] = PN_MEDIA_SOS ;
dev - > addr_len = 1 ;
dev - > tx_queue_len = SSIP_TXQUEUE_LEN ;
2017-06-08 10:16:05 -04:00
dev - > needs_free_netdev = true ;
2013-11-15 10:50:32 +00:00
dev - > header_ops = & phonet_header_ops ;
}
static int ssi_protocol_probe ( struct device * dev )
{
static const char ifname [ ] = " phonet%d " ;
struct hsi_client * cl = to_hsi_client ( dev ) ;
struct ssi_protocol * ssi ;
int err ;
ssi = kzalloc ( sizeof ( * ssi ) , GFP_KERNEL ) ;
if ( ! ssi ) {
dev_err ( dev , " No memory for ssi protocol \n " ) ;
return - ENOMEM ;
}
spin_lock_init ( & ssi - > lock ) ;
2017-10-04 16:26:59 -07:00
timer_setup ( & ssi - > rx_wd , ssip_rx_wd , TIMER_DEFERRABLE ) ;
timer_setup ( & ssi - > tx_wd , ssip_tx_wd , TIMER_DEFERRABLE ) ;
timer_setup ( & ssi - > keep_alive , ssip_keep_alive , 0 ) ;
2013-11-15 10:50:32 +00:00
INIT_LIST_HEAD ( & ssi - > txqueue ) ;
INIT_LIST_HEAD ( & ssi - > cmdqueue ) ;
atomic_set ( & ssi - > tx_usecnt , 0 ) ;
hsi_client_set_drvdata ( cl , ssi ) ;
ssi - > cl = cl ;
2016-06-18 00:58:39 +02:00
INIT_WORK ( & ssi - > work , ssip_xmit_work ) ;
2013-11-15 10:50:32 +00:00
ssi - > channel_id_cmd = hsi_get_channel_id_by_name ( cl , " mcsaab-control " ) ;
if ( ssi - > channel_id_cmd < 0 ) {
err = ssi - > channel_id_cmd ;
dev_err ( dev , " Could not get cmd channel (%d) \n " , err ) ;
goto out ;
}
ssi - > channel_id_data = hsi_get_channel_id_by_name ( cl , " mcsaab-data " ) ;
if ( ssi - > channel_id_data < 0 ) {
err = ssi - > channel_id_data ;
dev_err ( dev , " Could not get data channel (%d) \n " , err ) ;
goto out ;
}
err = ssip_alloc_cmds ( ssi ) ;
if ( err < 0 ) {
dev_err ( dev , " No memory for commands \n " ) ;
goto out ;
}
net: set name_assign_type in alloc_netdev()
Extend alloc_netdev{,_mq{,s}}() to take name_assign_type as argument, and convert
all users to pass NET_NAME_UNKNOWN.
Coccinelle patch:
@@
expression sizeof_priv, name, setup, txqs, rxqs, count;
@@
(
-alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs)
+alloc_netdev_mqs(sizeof_priv, name, NET_NAME_UNKNOWN, setup, txqs, rxqs)
|
-alloc_netdev_mq(sizeof_priv, name, setup, count)
+alloc_netdev_mq(sizeof_priv, name, NET_NAME_UNKNOWN, setup, count)
|
-alloc_netdev(sizeof_priv, name, setup)
+alloc_netdev(sizeof_priv, name, NET_NAME_UNKNOWN, setup)
)
v9: move comments here from the wrong commit
Signed-off-by: Tom Gundersen <teg@jklm.no>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-07-14 16:37:24 +02:00
ssi - > netdev = alloc_netdev ( 0 , ifname , NET_NAME_UNKNOWN , ssip_pn_setup ) ;
2013-11-15 10:50:32 +00:00
if ( ! ssi - > netdev ) {
dev_err ( dev , " No memory for netdev \n " ) ;
err = - ENOMEM ;
goto out1 ;
}
net: use core MTU range checking in misc drivers
firewire-net:
- set min/max_mtu
- remove fwnet_change_mtu
nes:
- set max_mtu
- clean up nes_netdev_change_mtu
xpnet:
- set min/max_mtu
- remove xpnet_dev_change_mtu
hippi:
- set min/max_mtu
- remove hippi_change_mtu
batman-adv:
- set max_mtu
- remove batadv_interface_change_mtu
- initialization is a little async, not 100% certain that max_mtu is set
in the optimal place, don't have hardware to test with
rionet:
- set min/max_mtu
- remove rionet_change_mtu
slip:
- set min/max_mtu
- streamline sl_change_mtu
um/net_kern:
- remove pointless ndo_change_mtu
hsi/clients/ssi_protocol:
- use core MTU range checking
- remove now redundant ssip_pn_set_mtu
ipoib:
- set a default max MTU value
- Note: ipoib's actual max MTU can vary, depending on if the device is in
connected mode or not, so we'll just set the max_mtu value to the max
possible, and let the ndo_change_mtu function continue to validate any new
MTU change requests with checks for CM or not. Note that ipoib has no
min_mtu set, and thus, the network core's mtu > 0 check is the only lower
bounds here.
mptlan:
- use net core MTU range checking
- remove now redundant mpt_lan_change_mtu
fddi:
- min_mtu = 21, max_mtu = 4470
- remove now redundant fddi_change_mtu (including export)
fjes:
- min_mtu = 8192, max_mtu = 65536
- The max_mtu value is actually one over IP_MAX_MTU here, but the idea is to
get past the core net MTU range checks so fjes_change_mtu can validate a
new MTU against what it supports (see fjes_support_mtu in fjes_hw.c)
hsr:
- min_mtu = 0 (calls ether_setup, max_mtu is 1500)
f_phonet:
- min_mtu = 6, max_mtu = 65541
u_ether:
- min_mtu = 14, max_mtu = 15412
phonet/pep-gprs:
- min_mtu = 576, max_mtu = 65530
- remove redundant gprs_set_mtu
CC: netdev@vger.kernel.org
CC: linux-rdma@vger.kernel.org
CC: Stefan Richter <stefanr@s5r6.in-berlin.de>
CC: Faisal Latif <faisal.latif@intel.com>
CC: linux-rdma@vger.kernel.org
CC: Cliff Whickman <cpw@sgi.com>
CC: Robin Holt <robinmholt@gmail.com>
CC: Jes Sorensen <jes@trained-monkey.org>
CC: Marek Lindner <mareklindner@neomailbox.ch>
CC: Simon Wunderlich <sw@simonwunderlich.de>
CC: Antonio Quartulli <a@unstable.cc>
CC: Sathya Prakash <sathya.prakash@broadcom.com>
CC: Chaitra P B <chaitra.basappa@broadcom.com>
CC: Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
CC: MPT-FusionLinux.pdl@broadcom.com
CC: Sebastian Reichel <sre@kernel.org>
CC: Felipe Balbi <balbi@kernel.org>
CC: Arvid Brodin <arvid.brodin@alten.se>
CC: Remi Denis-Courmont <courmisch@gmail.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-10-20 13:55:22 -04:00
/* MTU range: 6 - 65535 */
ssi - > netdev - > min_mtu = PHONET_MIN_MTU ;
ssi - > netdev - > max_mtu = SSIP_MAX_MTU ;
2013-11-15 10:50:32 +00:00
SET_NETDEV_DEV ( ssi - > netdev , dev ) ;
netif_carrier_off ( ssi - > netdev ) ;
err = register_netdev ( ssi - > netdev ) ;
if ( err < 0 ) {
dev_err ( dev , " Register netdev failed (%d) \n " , err ) ;
goto out2 ;
}
list_add ( & ssi - > link , & ssip_list ) ;
dev_dbg ( dev , " channel configuration: cmd=%d, data=%d \n " ,
ssi - > channel_id_cmd , ssi - > channel_id_data ) ;
return 0 ;
out2 :
free_netdev ( ssi - > netdev ) ;
out1 :
ssip_free_cmds ( ssi ) ;
out :
kfree ( ssi ) ;
return err ;
}
static int ssi_protocol_remove ( struct device * dev )
{
struct hsi_client * cl = to_hsi_client ( dev ) ;
struct ssi_protocol * ssi = hsi_client_drvdata ( cl ) ;
list_del ( & ssi - > link ) ;
unregister_netdev ( ssi - > netdev ) ;
ssip_free_cmds ( ssi ) ;
hsi_client_set_drvdata ( cl , NULL ) ;
kfree ( ssi ) ;
return 0 ;
}
static struct hsi_client_driver ssip_driver = {
. driver = {
. name = " ssi-protocol " ,
. owner = THIS_MODULE ,
. probe = ssi_protocol_probe ,
. remove = ssi_protocol_remove ,
} ,
} ;
static int __init ssip_init ( void )
{
pr_info ( " SSI protocol aka McSAAB added \n " ) ;
return hsi_register_client_driver ( & ssip_driver ) ;
}
module_init ( ssip_init ) ;
static void __exit ssip_exit ( void )
{
hsi_unregister_client_driver ( & ssip_driver ) ;
pr_info ( " SSI protocol driver removed \n " ) ;
}
module_exit ( ssip_exit ) ;
MODULE_ALIAS ( " hsi:ssi-protocol " ) ;
MODULE_AUTHOR ( " Carlos Chinea <carlos.chinea@nokia.com> " ) ;
MODULE_AUTHOR ( " Remi Denis-Courmont <remi.denis-courmont@nokia.com> " ) ;
MODULE_DESCRIPTION ( " SSI protocol improved aka McSAAB " ) ;
MODULE_LICENSE ( " GPL " ) ;