2020-08-19 08:23:57 +01:00
/*
2014-03-16 03:47:02 +05:30
* Copyright ( c ) 2014 Redpine Signals Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
2017-05-16 15:31:16 +05:30
# include <linux/firmware.h>
2018-02-27 19:56:16 +05:30
# include <net/bluetooth/bluetooth.h>
2014-03-16 03:47:02 +05:30
# include "rsi_mgmt.h"
2017-05-16 15:31:16 +05:30
# include "rsi_hal.h"
# include "rsi_sdio.h"
2017-08-16 18:43:14 +05:30
# include "rsi_common.h"
2017-05-16 15:31:16 +05:30
/* FLASH Firmware */
static struct ta_metadata metadata_flash_content [ ] = {
{ " flash_content " , 0x00010000 } ,
2017-05-26 20:31:31 +05:30
{ " rsi/rs9113_wlan_qspi.rps " , 0x00010000 } ,
2018-02-27 19:56:16 +05:30
{ " rsi/rs9113_wlan_bt_dual_mode.rps " , 0x00010000 } ,
2018-07-16 19:09:34 +05:30
{ " flash_content " , 0x00010000 } ,
{ " rsi/rs9113_ap_bt_dual_mode.rps " , 0x00010000 } ,
2017-05-16 15:31:16 +05:30
} ;
2014-03-16 03:47:02 +05:30
2019-04-03 09:43:04 +05:30
static struct ta_metadata metadata [ ] = { { " pmemdata_dummy " , 0x00000000 } ,
{ " rsi/rs9116_wlan.rps " , 0x00000000 } ,
{ " rsi/rs9116_wlan_bt_classic.rps " , 0x00000000 } ,
{ " rsi/pmemdata_dummy " , 0x00000000 } ,
{ " rsi/rs9116_wlan_bt_classic.rps " , 0x00000000 }
} ;
2017-08-16 18:43:11 +05:30
int rsi_send_pkt_to_bus ( struct rsi_common * common , struct sk_buff * skb )
{
struct rsi_hw * adapter = common - > priv ;
int status ;
2018-02-27 19:56:14 +05:30
if ( common - > coex_mode > 1 )
mutex_lock ( & common - > tx_bus_mutex ) ;
2017-08-16 18:43:11 +05:30
status = adapter - > host_intf_ops - > write_pkt ( common - > priv ,
skb - > data , skb - > len ) ;
2018-02-27 19:56:14 +05:30
if ( common - > coex_mode > 1 )
mutex_unlock ( & common - > tx_bus_mutex ) ;
2017-08-16 18:43:11 +05:30
return status ;
}
2017-07-06 20:07:16 +05:30
2018-03-29 19:44:50 +05:30
int rsi_prepare_mgmt_desc ( struct rsi_common * common , struct sk_buff * skb )
2017-07-06 20:07:16 +05:30
{
struct rsi_hw * adapter = common - > priv ;
struct ieee80211_hdr * wh = NULL ;
struct ieee80211_tx_info * info ;
struct ieee80211_conf * conf = & adapter - > hw - > conf ;
2017-08-30 15:08:24 +05:30
struct ieee80211_vif * vif ;
2017-07-06 20:07:16 +05:30
struct rsi_mgmt_desc * mgmt_desc ;
struct skb_info * tx_params ;
2018-03-29 19:44:49 +05:30
struct rsi_xtended_desc * xtend_desc = NULL ;
2017-07-06 20:07:16 +05:30
u8 header_size ;
u32 dword_align_bytes = 0 ;
2017-08-16 18:43:14 +05:30
if ( skb - > len > MAX_MGMT_PKT_SIZE ) {
rsi_dbg ( INFO_ZONE , " %s: Dropping mgmt pkt > 512 \n " , __func__ ) ;
return - EINVAL ;
}
2017-07-06 20:07:16 +05:30
info = IEEE80211_SKB_CB ( skb ) ;
tx_params = ( struct skb_info * ) info - > driver_data ;
2017-08-30 15:08:24 +05:30
vif = tx_params - > vif ;
2017-07-06 20:07:16 +05:30
/* Update header size */
2018-03-29 19:44:49 +05:30
header_size = FRAME_DESC_SZ + sizeof ( struct rsi_xtended_desc ) ;
2017-07-06 20:07:16 +05:30
if ( header_size > skb_headroom ( skb ) ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to add extended descriptor \n " ,
__func__ ) ;
return - ENOSPC ;
}
skb_push ( skb , header_size ) ;
dword_align_bytes = ( ( unsigned long ) skb - > data & 0x3f ) ;
if ( dword_align_bytes > skb_headroom ( skb ) ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to add dword align \n " , __func__ ) ;
return - ENOSPC ;
}
skb_push ( skb , dword_align_bytes ) ;
header_size + = dword_align_bytes ;
tx_params - > internal_hdr_size = header_size ;
memset ( & skb - > data [ 0 ] , 0 , header_size ) ;
wh = ( struct ieee80211_hdr * ) & skb - > data [ header_size ] ;
mgmt_desc = ( struct rsi_mgmt_desc * ) skb - > data ;
2018-03-29 19:44:49 +05:30
xtend_desc = ( struct rsi_xtended_desc * ) & skb - > data [ FRAME_DESC_SZ ] ;
2017-07-06 20:07:16 +05:30
rsi_set_len_qno ( & mgmt_desc - > len_qno , ( skb - > len - FRAME_DESC_SZ ) ,
RSI_WIFI_MGMT_Q ) ;
mgmt_desc - > frame_type = TX_DOT11_MGMT ;
mgmt_desc - > header_len = MIN_802_11_HDR_LEN ;
mgmt_desc - > xtend_desc_size = header_size - FRAME_DESC_SZ ;
2018-12-27 14:56:18 +05:30
if ( ieee80211_is_probe_req ( wh - > frame_control ) )
mgmt_desc - > frame_info = cpu_to_le16 ( RSI_INSERT_SEQ_IN_FW ) ;
2017-07-06 20:07:16 +05:30
mgmt_desc - > frame_info | = cpu_to_le16 ( RATE_INFO_ENABLE ) ;
if ( is_broadcast_ether_addr ( wh - > addr1 ) )
mgmt_desc - > frame_info | = cpu_to_le16 ( RSI_BROADCAST_PKT ) ;
mgmt_desc - > seq_ctrl =
cpu_to_le16 ( IEEE80211_SEQ_TO_SN ( le16_to_cpu ( wh - > seq_ctrl ) ) ) ;
2017-08-30 15:08:24 +05:30
if ( ( common - > band = = NL80211_BAND_2GHZ ) & & ! common - > p2p_enabled )
mgmt_desc - > rate_info = cpu_to_le16 ( RSI_RATE_1 ) ;
2017-07-06 20:07:16 +05:30
else
2017-08-30 15:08:24 +05:30
mgmt_desc - > rate_info = cpu_to_le16 ( RSI_RATE_6 ) ;
2017-07-06 20:07:16 +05:30
if ( conf_is_ht40 ( conf ) )
mgmt_desc - > bbp_info = cpu_to_le16 ( FULL40M_ENABLE ) ;
2017-08-16 18:43:14 +05:30
if ( ieee80211_is_probe_resp ( wh - > frame_control ) ) {
mgmt_desc - > misc_flags | = ( RSI_ADD_DELTA_TSF_VAP_ID |
RSI_FETCH_RETRY_CNT_FRM_HST ) ;
# define PROBE_RESP_RETRY_CNT 3
xtend_desc - > retry_cnt = PROBE_RESP_RETRY_CNT ;
}
2017-08-30 15:08:24 +05:30
if ( ( ( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_P2P_GO ) ) & &
2017-08-16 18:43:14 +05:30
( ieee80211_is_action ( wh - > frame_control ) ) ) {
struct rsi_sta * rsta = rsi_find_sta ( common , wh - > addr1 ) ;
if ( rsta )
mgmt_desc - > sta_id = tx_params - > sta_id ;
else
return - EINVAL ;
}
2017-08-30 15:08:24 +05:30
mgmt_desc - > rate_info | =
cpu_to_le16 ( ( tx_params - > vap_id < < RSI_DESC_VAP_ID_OFST ) &
RSI_DESC_VAP_ID_MASK ) ;
2017-07-06 20:07:16 +05:30
return 0 ;
}
2017-07-06 20:07:19 +05:30
/* This function prepares descriptor for given data packet */
2018-03-29 19:44:50 +05:30
int rsi_prepare_data_desc ( struct rsi_common * common , struct sk_buff * skb )
2014-03-16 03:47:02 +05:30
{
2017-08-03 19:58:59 +05:30
struct rsi_hw * adapter = common - > priv ;
struct ieee80211_vif * vif ;
2017-07-06 20:07:18 +05:30
struct ieee80211_hdr * wh = NULL ;
2014-03-16 03:47:02 +05:30
struct ieee80211_tx_info * info ;
struct skb_info * tx_params ;
2017-07-06 20:07:17 +05:30
struct rsi_data_desc * data_desc ;
2018-03-29 19:44:49 +05:30
struct rsi_xtended_desc * xtend_desc ;
2014-03-16 03:47:02 +05:30
u8 ieee80211_size = MIN_802_11_HDR_LEN ;
2017-07-06 20:07:18 +05:30
u8 header_size ;
u8 vap_id = 0 ;
u8 dword_align_bytes ;
2016-03-18 13:25:33 +11:00
u16 seq_num ;
2014-03-16 03:47:02 +05:30
info = IEEE80211_SKB_CB ( skb ) ;
2017-08-30 15:08:25 +05:30
vif = info - > control . vif ;
2014-03-16 03:47:02 +05:30
tx_params = ( struct skb_info * ) info - > driver_data ;
2018-03-29 19:44:49 +05:30
header_size = FRAME_DESC_SZ + sizeof ( struct rsi_xtended_desc ) ;
2017-07-06 20:07:18 +05:30
if ( header_size > skb_headroom ( skb ) ) {
2014-03-16 03:47:02 +05:30
rsi_dbg ( ERR_ZONE , " %s: Unable to send pkt \n " , __func__ ) ;
2017-07-06 20:07:19 +05:30
return - ENOSPC ;
2014-03-16 03:47:02 +05:30
}
2017-07-06 20:07:18 +05:30
skb_push ( skb , header_size ) ;
dword_align_bytes = ( ( unsigned long ) skb - > data & 0x3f ) ;
if ( header_size > skb_headroom ( skb ) ) {
rsi_dbg ( ERR_ZONE , " %s: Not enough headroom \n " , __func__ ) ;
2017-07-06 20:07:19 +05:30
return - ENOSPC ;
2017-07-06 20:07:18 +05:30
}
skb_push ( skb , dword_align_bytes ) ;
header_size + = dword_align_bytes ;
2014-03-16 03:47:02 +05:30
2017-07-06 20:07:18 +05:30
tx_params - > internal_hdr_size = header_size ;
2017-07-06 20:07:17 +05:30
data_desc = ( struct rsi_data_desc * ) skb - > data ;
2017-07-06 20:07:18 +05:30
memset ( data_desc , 0 , header_size ) ;
2018-03-29 19:44:49 +05:30
xtend_desc = ( struct rsi_xtended_desc * ) & skb - > data [ FRAME_DESC_SZ ] ;
2017-07-06 20:07:18 +05:30
wh = ( struct ieee80211_hdr * ) & skb - > data [ header_size ] ;
2017-08-16 18:43:14 +05:30
seq_num = IEEE80211_SEQ_TO_SN ( le16_to_cpu ( wh - > seq_ctrl ) ) ;
2017-07-06 20:07:18 +05:30
data_desc - > xtend_desc_size = header_size - FRAME_DESC_SZ ;
2014-03-16 03:47:02 +05:30
2017-07-06 20:07:18 +05:30
if ( ieee80211_is_data_qos ( wh - > frame_control ) ) {
2014-03-16 03:47:02 +05:30
ieee80211_size + = 2 ;
2017-07-06 20:07:17 +05:30
data_desc - > mac_flags | = cpu_to_le16 ( RSI_QOS_ENABLE ) ;
2014-03-16 03:47:02 +05:30
}
2017-08-30 15:08:25 +05:30
if ( ( ( vif - > type = = NL80211_IFTYPE_STATION ) | |
( vif - > type = = NL80211_IFTYPE_P2P_CLIENT ) ) & &
2017-08-03 19:58:59 +05:30
( adapter - > ps_state = = PS_ENABLED ) )
wh - > frame_control | = cpu_to_le16 ( RSI_SET_PS_ENABLE ) ;
2014-03-16 03:47:02 +05:30
if ( ( ! ( info - > flags & IEEE80211_TX_INTFL_DONT_ENCRYPT ) ) & &
( common - > secinfo . security_enable ) ) {
if ( rsi_is_cipher_wep ( common ) )
ieee80211_size + = 4 ;
else
ieee80211_size + = 8 ;
2017-07-06 20:07:17 +05:30
data_desc - > mac_flags | = cpu_to_le16 ( RSI_ENCRYPT_PKT ) ;
2014-03-16 03:47:02 +05:30
}
2017-07-06 20:07:17 +05:30
rsi_set_len_qno ( & data_desc - > len_qno , ( skb - > len - FRAME_DESC_SZ ) ,
RSI_WIFI_DATA_Q ) ;
data_desc - > header_len = ieee80211_size ;
2014-03-16 03:47:02 +05:30
2017-07-06 20:07:17 +05:30
if ( common - > min_rate ! = RSI_RATE_AUTO ) {
2014-03-16 03:47:02 +05:30
/* Send fixed rate */
2017-07-06 20:07:17 +05:30
data_desc - > frame_info = cpu_to_le16 ( RATE_INFO_ENABLE ) ;
data_desc - > rate_info = cpu_to_le16 ( common - > min_rate ) ;
2014-06-16 19:47:03 +05:30
if ( conf_is_ht40 ( & common - > priv - > hw - > conf ) )
2017-07-06 20:07:17 +05:30
data_desc - > bbp_info = cpu_to_le16 ( FULL40M_ENABLE ) ;
2014-06-16 19:47:03 +05:30
2017-08-16 18:43:14 +05:30
if ( ( common - > vif_info [ 0 ] . sgi ) & & ( common - > min_rate & 0x100 ) ) {
/* Only MCS rates */
data_desc - > rate_info | =
cpu_to_le16 ( ENABLE_SHORTGI_RATE ) ;
2014-06-16 19:43:54 +05:30
}
2017-07-06 20:07:18 +05:30
}
if ( skb - > protocol = = cpu_to_be16 ( ETH_P_PAE ) ) {
rsi_dbg ( INFO_ZONE , " *** Tx EAPOL *** \n " ) ;
data_desc - > frame_info = cpu_to_le16 ( RATE_INFO_ENABLE ) ;
if ( common - > band = = NL80211_BAND_5GHZ )
data_desc - > rate_info = cpu_to_le16 ( RSI_RATE_6 ) ;
else
data_desc - > rate_info = cpu_to_le16 ( RSI_RATE_1 ) ;
data_desc - > mac_flags | = cpu_to_le16 ( RSI_REKEY_PURPOSE ) ;
data_desc - > misc_flags | = RSI_FETCH_RETRY_CNT_FRM_HST ;
# define EAPOL_RETRY_CNT 15
xtend_desc - > retry_cnt = EAPOL_RETRY_CNT ;
2018-03-29 19:44:52 +05:30
if ( common - > eapol4_confirm )
skb - > priority = VO_Q ;
else
rsi_set_len_qno ( & data_desc - > len_qno ,
( skb - > len - FRAME_DESC_SZ ) ,
RSI_WIFI_MGMT_Q ) ;
if ( ( skb - > len - header_size ) = = EAPOL4_PACKET_LEN ) {
data_desc - > misc_flags | =
RSI_DESC_REQUIRE_CFM_TO_HOST ;
xtend_desc - > confirm_frame_type = EAPOL4_CONFIRM ;
}
2014-03-16 03:47:02 +05:30
}
2018-07-05 18:08:19 +05:30
data_desc - > mac_flags | = cpu_to_le16 ( seq_num & 0xfff ) ;
2017-07-06 20:07:17 +05:30
data_desc - > qid_tid = ( ( skb - > priority & 0xf ) |
( ( tx_params - > tid & 0xf ) < < 4 ) ) ;
data_desc - > sta_id = tx_params - > sta_id ;
2014-03-16 03:47:02 +05:30
2017-07-06 20:07:18 +05:30
if ( ( is_broadcast_ether_addr ( wh - > addr1 ) ) | |
( is_multicast_ether_addr ( wh - > addr1 ) ) ) {
data_desc - > frame_info = cpu_to_le16 ( RATE_INFO_ENABLE ) ;
data_desc - > frame_info | = cpu_to_le16 ( RSI_BROADCAST_PKT ) ;
data_desc - > sta_id = vap_id ;
2017-08-16 18:43:14 +05:30
2017-08-30 15:08:25 +05:30
if ( ( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_P2P_GO ) ) {
2017-08-16 18:43:14 +05:30
if ( common - > band = = NL80211_BAND_5GHZ )
data_desc - > rate_info = cpu_to_le16 ( RSI_RATE_6 ) ;
else
data_desc - > rate_info = cpu_to_le16 ( RSI_RATE_1 ) ;
}
2017-07-06 20:07:18 +05:30
}
2017-08-30 15:08:25 +05:30
if ( ( ( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_P2P_GO ) ) & &
2017-08-16 18:43:14 +05:30
( ieee80211_has_moredata ( wh - > frame_control ) ) )
data_desc - > frame_info | = cpu_to_le16 ( MORE_DATA_PRESENT ) ;
2017-07-06 20:07:18 +05:30
2017-08-30 15:08:25 +05:30
data_desc - > rate_info | =
cpu_to_le16 ( ( tx_params - > vap_id < < RSI_DESC_VAP_ID_OFST ) &
RSI_DESC_VAP_ID_MASK ) ;
2017-07-06 20:07:19 +05:30
return 0 ;
}
/* This function sends received data packet from driver to device */
int rsi_send_data_pkt ( struct rsi_common * common , struct sk_buff * skb )
{
struct rsi_hw * adapter = common - > priv ;
2017-08-30 15:08:25 +05:30
struct ieee80211_vif * vif ;
2017-07-06 20:07:19 +05:30
struct ieee80211_tx_info * info ;
struct ieee80211_bss_conf * bss ;
2017-08-16 18:43:14 +05:30
int status = - EINVAL ;
if ( ! skb )
return 0 ;
if ( common - > iface_down )
goto err ;
2017-07-06 20:07:19 +05:30
info = IEEE80211_SKB_CB ( skb ) ;
2017-08-16 18:43:14 +05:30
if ( ! info - > control . vif )
goto err ;
2017-08-30 15:08:25 +05:30
vif = info - > control . vif ;
bss = & vif - > bss_conf ;
2017-07-06 20:07:19 +05:30
2017-08-30 15:08:25 +05:30
if ( ( ( vif - > type = = NL80211_IFTYPE_STATION ) | |
( vif - > type = = NL80211_IFTYPE_P2P_CLIENT ) ) & &
( ! bss - > assoc ) )
2017-07-06 20:07:19 +05:30
goto err ;
2018-02-27 19:56:14 +05:30
status = rsi_send_pkt_to_bus ( common , skb ) ;
2014-03-16 03:47:02 +05:30
if ( status )
2017-07-06 20:07:19 +05:30
rsi_dbg ( ERR_ZONE , " %s: Failed to write pkt \n " , __func__ ) ;
2014-03-16 03:47:02 +05:30
err :
+ + common - > tx_stats . total_tx_pkt_freed [ skb - > priority ] ;
2017-07-06 20:07:17 +05:30
rsi_indicate_tx_status ( adapter , skb , status ) ;
2014-03-16 03:47:02 +05:30
return status ;
}
/**
* rsi_send_mgmt_pkt ( ) - This functions sends the received management packet
* from driver to device .
* @ common : Pointer to the driver private structure .
* @ skb : Pointer to the socket buffer structure .
*
* Return : status : 0 on success , - 1 on failure .
*/
int rsi_send_mgmt_pkt ( struct rsi_common * common ,
struct sk_buff * skb )
{
struct rsi_hw * adapter = common - > priv ;
2018-03-29 19:44:50 +05:30
struct ieee80211_bss_conf * bss ;
struct ieee80211_hdr * wh ;
2014-03-16 03:47:02 +05:30
struct ieee80211_tx_info * info ;
struct skb_info * tx_params ;
2018-03-29 19:44:50 +05:30
struct rsi_mgmt_desc * mgmt_desc ;
struct rsi_xtended_desc * xtend_desc ;
2014-03-16 03:47:02 +05:30
int status = - E2BIG ;
2018-03-29 19:44:50 +05:30
u8 header_size ;
2014-03-16 03:47:02 +05:30
info = IEEE80211_SKB_CB ( skb ) ;
tx_params = ( struct skb_info * ) info - > driver_data ;
2018-03-29 19:44:50 +05:30
header_size = tx_params - > internal_hdr_size ;
2014-03-16 03:47:02 +05:30
if ( tx_params - > flags & INTERNAL_MGMT_PKT ) {
2017-05-16 15:31:14 +05:30
status = adapter - > host_intf_ops - > write_pkt ( common - > priv ,
( u8 * ) skb - > data ,
skb - > len ) ;
2014-03-16 03:47:02 +05:30
if ( status ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to write the packet \n " , __func__ ) ;
}
dev_kfree_skb ( skb ) ;
return status ;
}
2018-03-29 19:44:50 +05:30
bss = & info - > control . vif - > bss_conf ;
wh = ( struct ieee80211_hdr * ) & skb - > data [ header_size ] ;
mgmt_desc = ( struct rsi_mgmt_desc * ) skb - > data ;
xtend_desc = ( struct rsi_xtended_desc * ) & skb - > data [ FRAME_DESC_SZ ] ;
/* Indicate to firmware to give cfm for probe */
if ( ieee80211_is_probe_req ( wh - > frame_control ) & & ! bss - > assoc ) {
rsi_dbg ( INFO_ZONE ,
" %s: blocking mgmt queue \n " , __func__ ) ;
mgmt_desc - > misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST ;
xtend_desc - > confirm_frame_type = PROBEREQ_CONFIRM ;
common - > mgmt_q_block = true ;
rsi_dbg ( INFO_ZONE , " Mgmt queue blocked \n " ) ;
}
2014-03-16 03:47:02 +05:30
2018-02-27 19:56:14 +05:30
status = rsi_send_pkt_to_bus ( common , skb ) ;
2014-03-16 03:47:02 +05:30
if ( status )
rsi_dbg ( ERR_ZONE , " %s: Failed to write the packet \n " , __func__ ) ;
rsi_indicate_tx_status ( common - > priv , skb , status ) ;
return status ;
}
2017-05-16 15:31:16 +05:30
2018-02-27 19:56:16 +05:30
int rsi_send_bt_pkt ( struct rsi_common * common , struct sk_buff * skb )
{
int status = - EINVAL ;
u8 header_size = 0 ;
struct rsi_bt_desc * bt_desc ;
u8 queueno = ( ( skb - > data [ 1 ] > > 4 ) & 0xf ) ;
if ( queueno = = RSI_BT_MGMT_Q ) {
status = rsi_send_pkt_to_bus ( common , skb ) ;
if ( status )
rsi_dbg ( ERR_ZONE , " %s: Failed to write bt mgmt pkt \n " ,
__func__ ) ;
goto out ;
}
header_size = FRAME_DESC_SZ ;
if ( header_size > skb_headroom ( skb ) ) {
rsi_dbg ( ERR_ZONE , " %s: Not enough headroom \n " , __func__ ) ;
status = - ENOSPC ;
goto out ;
}
skb_push ( skb , header_size ) ;
memset ( skb - > data , 0 , header_size ) ;
bt_desc = ( struct rsi_bt_desc * ) skb - > data ;
rsi_set_len_qno ( & bt_desc - > len_qno , ( skb - > len - FRAME_DESC_SZ ) ,
RSI_BT_DATA_Q ) ;
bt_desc - > bt_pkt_type = cpu_to_le16 ( bt_cb ( skb ) - > pkt_type ) ;
status = rsi_send_pkt_to_bus ( common , skb ) ;
if ( status )
rsi_dbg ( ERR_ZONE , " %s: Failed to write bt pkt \n " , __func__ ) ;
out :
dev_kfree_skb ( skb ) ;
return status ;
}
2017-08-16 18:43:11 +05:30
int rsi_prepare_beacon ( struct rsi_common * common , struct sk_buff * skb )
{
struct rsi_hw * adapter = ( struct rsi_hw * ) common - > priv ;
struct rsi_data_desc * bcn_frm ;
struct ieee80211_hw * hw = common - > priv - > hw ;
struct ieee80211_conf * conf = & hw - > conf ;
2017-08-30 15:08:24 +05:30
struct ieee80211_vif * vif ;
2017-08-16 18:43:11 +05:30
struct sk_buff * mac_bcn ;
2017-08-30 15:08:24 +05:30
u8 vap_id = 0 , i ;
u16 tim_offset = 0 ;
for ( i = 0 ; i < RSI_MAX_VIFS ; i + + ) {
vif = adapter - > vifs [ i ] ;
if ( ! vif )
continue ;
if ( ( vif - > type = = NL80211_IFTYPE_AP ) | |
( vif - > type = = NL80211_IFTYPE_P2P_GO ) )
break ;
}
if ( ! vif )
return - EINVAL ;
2017-08-16 18:43:11 +05:30
mac_bcn = ieee80211_beacon_get_tim ( adapter - > hw ,
2017-08-30 15:08:24 +05:30
vif ,
2017-08-16 18:43:11 +05:30
& tim_offset , NULL ) ;
if ( ! mac_bcn ) {
rsi_dbg ( ERR_ZONE , " Failed to get beacon from mac80211 \n " ) ;
return - EINVAL ;
}
common - > beacon_cnt + + ;
bcn_frm = ( struct rsi_data_desc * ) skb - > data ;
rsi_set_len_qno ( & bcn_frm - > len_qno , mac_bcn - > len , RSI_WIFI_DATA_Q ) ;
bcn_frm - > header_len = MIN_802_11_HDR_LEN ;
bcn_frm - > frame_info = cpu_to_le16 ( RSI_DATA_DESC_MAC_BBP_INFO |
RSI_DATA_DESC_NO_ACK_IND |
RSI_DATA_DESC_BEACON_FRAME |
RSI_DATA_DESC_INSERT_TSF |
RSI_DATA_DESC_INSERT_SEQ_NO |
RATE_INFO_ENABLE ) ;
bcn_frm - > rate_info = cpu_to_le16 ( vap_id < < 14 ) ;
bcn_frm - > qid_tid = BEACON_HW_Q ;
if ( conf_is_ht40_plus ( conf ) ) {
bcn_frm - > bbp_info = cpu_to_le16 ( LOWER_20_ENABLE ) ;
bcn_frm - > bbp_info | = cpu_to_le16 ( LOWER_20_ENABLE > > 12 ) ;
} else if ( conf_is_ht40_minus ( conf ) ) {
bcn_frm - > bbp_info = cpu_to_le16 ( UPPER_20_ENABLE ) ;
bcn_frm - > bbp_info | = cpu_to_le16 ( UPPER_20_ENABLE > > 12 ) ;
}
if ( common - > band = = NL80211_BAND_2GHZ )
bcn_frm - > bbp_info | = cpu_to_le16 ( RSI_RATE_1 ) ;
else
bcn_frm - > bbp_info | = cpu_to_le16 ( RSI_RATE_6 ) ;
if ( mac_bcn - > data [ tim_offset + 2 ] = = 0 )
bcn_frm - > frame_info | = cpu_to_le16 ( RSI_DATA_DESC_DTIM_BEACON ) ;
memcpy ( & skb - > data [ FRAME_DESC_SZ ] , mac_bcn - > data , mac_bcn - > len ) ;
skb_put ( skb , mac_bcn - > len + FRAME_DESC_SZ ) ;
dev_kfree_skb ( mac_bcn ) ;
return 0 ;
}
2017-10-24 02:29:09 -07:00
static void bl_cmd_timeout ( struct timer_list * t )
2017-05-16 15:31:16 +05:30
{
2017-10-24 02:29:09 -07:00
struct rsi_hw * adapter = from_timer ( adapter , t , bl_cmd_timer ) ;
2017-05-16 15:31:16 +05:30
adapter - > blcmd_timer_expired = true ;
del_timer ( & adapter - > bl_cmd_timer ) ;
}
static int bl_start_cmd_timer ( struct rsi_hw * adapter , u32 timeout )
{
2017-10-24 02:29:09 -07:00
timer_setup ( & adapter - > bl_cmd_timer , bl_cmd_timeout , 0 ) ;
2017-05-16 15:31:16 +05:30
adapter - > bl_cmd_timer . expires = ( msecs_to_jiffies ( timeout ) + jiffies ) ;
adapter - > blcmd_timer_expired = false ;
add_timer ( & adapter - > bl_cmd_timer ) ;
return 0 ;
}
static int bl_stop_cmd_timer ( struct rsi_hw * adapter )
{
adapter - > blcmd_timer_expired = false ;
if ( timer_pending ( & adapter - > bl_cmd_timer ) )
del_timer ( & adapter - > bl_cmd_timer ) ;
return 0 ;
}
static int bl_write_cmd ( struct rsi_hw * adapter , u8 cmd , u8 exp_resp ,
u16 * cmd_resp )
{
struct rsi_host_intf_ops * hif_ops = adapter - > host_intf_ops ;
u32 regin_val = 0 , regout_val = 0 ;
u32 regin_input = 0 ;
u8 output = 0 ;
int status ;
regin_input = ( REGIN_INPUT | adapter - > priv - > coex_mode ) ;
while ( ! adapter - > blcmd_timer_expired ) {
regin_val = 0 ;
status = hif_ops - > master_reg_read ( adapter , SWBL_REGIN ,
& regin_val , 2 ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Command %0x REGIN reading failed.. \n " ,
__func__ , cmd ) ;
return status ;
}
mdelay ( 1 ) ;
if ( ( regin_val > > 12 ) ! = REGIN_VALID )
break ;
}
if ( adapter - > blcmd_timer_expired ) {
rsi_dbg ( ERR_ZONE ,
" %s: Command %0x REGIN reading timed out.. \n " ,
__func__ , cmd ) ;
return - ETIMEDOUT ;
}
rsi_dbg ( INFO_ZONE ,
" Issuing write to Regin val:%0x sending cmd:%0x \n " ,
regin_val , ( cmd | regin_input < < 8 ) ) ;
status = hif_ops - > master_reg_write ( adapter , SWBL_REGIN ,
( cmd | regin_input < < 8 ) , 2 ) ;
if ( status < 0 )
return status ;
mdelay ( 1 ) ;
if ( cmd = = LOAD_HOSTED_FW | | cmd = = JUMP_TO_ZERO_PC ) {
/* JUMP_TO_ZERO_PC doesn't expect
* any response . So return from here
*/
return 0 ;
}
while ( ! adapter - > blcmd_timer_expired ) {
regout_val = 0 ;
status = hif_ops - > master_reg_read ( adapter , SWBL_REGOUT ,
& regout_val , 2 ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Command %0x REGOUT reading failed.. \n " ,
__func__ , cmd ) ;
return status ;
}
mdelay ( 1 ) ;
if ( ( regout_val > > 8 ) = = REGOUT_VALID )
break ;
}
if ( adapter - > blcmd_timer_expired ) {
rsi_dbg ( ERR_ZONE ,
" %s: Command %0x REGOUT reading timed out.. \n " ,
__func__ , cmd ) ;
return status ;
}
* cmd_resp = ( ( u16 * ) & regout_val ) [ 0 ] & 0xffff ;
output = ( ( u8 * ) & regout_val ) [ 0 ] & 0xff ;
status = hif_ops - > master_reg_write ( adapter , SWBL_REGOUT ,
( cmd | REGOUT_INVALID < < 8 ) , 2 ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Command %0x REGOUT writing failed.. \n " ,
__func__ , cmd ) ;
return status ;
}
mdelay ( 1 ) ;
if ( output ! = exp_resp ) {
rsi_dbg ( ERR_ZONE ,
" %s: Recvd resp %x for cmd %0x \n " ,
__func__ , output , cmd ) ;
return - EINVAL ;
}
rsi_dbg ( INFO_ZONE ,
" %s: Recvd Expected resp %x for cmd %0x \n " ,
__func__ , output , cmd ) ;
return 0 ;
}
static int bl_cmd ( struct rsi_hw * adapter , u8 cmd , u8 exp_resp , char * str )
{
u16 regout_val = 0 ;
u32 timeout ;
int status ;
if ( ( cmd = = EOF_REACHED ) | | ( cmd = = PING_VALID ) | | ( cmd = = PONG_VALID ) )
timeout = BL_BURN_TIMEOUT ;
else
timeout = BL_CMD_TIMEOUT ;
bl_start_cmd_timer ( adapter , timeout ) ;
status = bl_write_cmd ( adapter , cmd , exp_resp , & regout_val ) ;
if ( status < 0 ) {
2019-11-28 18:22:01 +01:00
bl_stop_cmd_timer ( adapter ) ;
2017-05-16 15:31:16 +05:30
rsi_dbg ( ERR_ZONE ,
" %s: Command %s (%0x) writing failed.. \n " ,
__func__ , str , cmd ) ;
return status ;
}
bl_stop_cmd_timer ( adapter ) ;
return 0 ;
}
# define CHECK_SUM_OFFSET 20
# define LEN_OFFSET 8
# define ADDR_OFFSET 16
static int bl_write_header ( struct rsi_hw * adapter , u8 * flash_content ,
u32 content_size )
{
struct rsi_host_intf_ops * hif_ops = adapter - > host_intf_ops ;
2018-04-11 12:13:31 +05:30
struct bl_header * bl_hdr ;
2017-05-16 15:31:16 +05:30
u32 write_addr , write_len ;
int status ;
2018-04-11 12:13:31 +05:30
bl_hdr = kzalloc ( sizeof ( * bl_hdr ) , GFP_KERNEL ) ;
if ( ! bl_hdr )
return - ENOMEM ;
bl_hdr - > flags = 0 ;
bl_hdr - > image_no = cpu_to_le32 ( adapter - > priv - > coex_mode ) ;
bl_hdr - > check_sum =
cpu_to_le32 ( * ( u32 * ) & flash_content [ CHECK_SUM_OFFSET ] ) ;
bl_hdr - > flash_start_address =
cpu_to_le32 ( * ( u32 * ) & flash_content [ ADDR_OFFSET ] ) ;
bl_hdr - > flash_len = cpu_to_le32 ( * ( u32 * ) & flash_content [ LEN_OFFSET ] ) ;
2017-05-16 15:31:16 +05:30
write_len = sizeof ( struct bl_header ) ;
if ( adapter - > rsi_host_intf = = RSI_HOST_INTF_USB ) {
write_addr = PING_BUFFER_ADDRESS ;
status = hif_ops - > write_reg_multiple ( adapter , write_addr ,
2018-04-11 12:13:31 +05:30
( u8 * ) bl_hdr , write_len ) ;
2017-05-16 15:31:16 +05:30
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to load Version/CRC structure \n " ,
__func__ ) ;
2018-04-11 12:13:31 +05:30
goto fail ;
2017-05-16 15:31:16 +05:30
}
} else {
write_addr = PING_BUFFER_ADDRESS > > 16 ;
status = hif_ops - > master_access_msword ( adapter , write_addr ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Unable to set ms word to common reg \n " ,
__func__ ) ;
2018-04-11 12:13:31 +05:30
goto fail ;
2017-05-16 15:31:16 +05:30
}
write_addr = RSI_SD_REQUEST_MASTER |
( PING_BUFFER_ADDRESS & 0xFFFF ) ;
status = hif_ops - > write_reg_multiple ( adapter , write_addr ,
2018-04-11 12:13:31 +05:30
( u8 * ) bl_hdr , write_len ) ;
2017-05-16 15:31:16 +05:30
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to load Version/CRC structure \n " ,
__func__ ) ;
2018-04-11 12:13:31 +05:30
goto fail ;
2017-05-16 15:31:16 +05:30
}
}
2018-04-11 12:13:31 +05:30
status = 0 ;
fail :
kfree ( bl_hdr ) ;
return status ;
2017-05-16 15:31:16 +05:30
}
static u32 read_flash_capacity ( struct rsi_hw * adapter )
{
u32 flash_sz = 0 ;
if ( ( adapter - > host_intf_ops - > master_reg_read ( adapter , FLASH_SIZE_ADDR ,
& flash_sz , 2 ) ) < 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Flash size reading failed.. \n " ,
__func__ ) ;
return 0 ;
}
rsi_dbg ( INIT_ZONE , " Flash capacity: %d KiloBytes \n " , flash_sz ) ;
return ( flash_sz * 1024 ) ; /* Return size in kbytes */
}
static int ping_pong_write ( struct rsi_hw * adapter , u8 cmd , u8 * addr , u32 size )
{
struct rsi_host_intf_ops * hif_ops = adapter - > host_intf_ops ;
u32 block_size = adapter - > block_size ;
u32 cmd_addr ;
u16 cmd_resp , cmd_req ;
u8 * str ;
int status ;
if ( cmd = = PING_WRITE ) {
cmd_addr = PING_BUFFER_ADDRESS ;
cmd_resp = PONG_AVAIL ;
cmd_req = PING_VALID ;
str = " PING_VALID " ;
} else {
cmd_addr = PONG_BUFFER_ADDRESS ;
cmd_resp = PING_AVAIL ;
cmd_req = PONG_VALID ;
str = " PONG_VALID " ;
}
status = hif_ops - > load_data_master_write ( adapter , cmd_addr , size ,
block_size , addr ) ;
if ( status ) {
rsi_dbg ( ERR_ZONE , " %s: Unable to write blk at addr %0x \n " ,
__func__ , * addr ) ;
return status ;
}
status = bl_cmd ( adapter , cmd_req , cmd_resp , str ) ;
2019-11-28 18:22:01 +01:00
if ( status )
2017-05-16 15:31:16 +05:30
return status ;
2019-11-28 18:22:01 +01:00
2017-05-16 15:31:16 +05:30
return 0 ;
}
static int auto_fw_upgrade ( struct rsi_hw * adapter , u8 * flash_content ,
u32 content_size )
{
2018-08-03 08:46:36 +01:00
u8 cmd ;
2017-05-16 15:31:16 +05:30
u32 temp_content_size , num_flash , index ;
u32 flash_start_address ;
int status ;
if ( content_size > MAX_FLASH_FILE_SIZE ) {
rsi_dbg ( ERR_ZONE ,
" %s: Flash Content size is more than 400K %u \n " ,
__func__ , MAX_FLASH_FILE_SIZE ) ;
return - EINVAL ;
}
flash_start_address = * ( u32 * ) & flash_content [ FLASH_START_ADDRESS ] ;
rsi_dbg ( INFO_ZONE , " flash start address: %08x \n " , flash_start_address ) ;
if ( flash_start_address < FW_IMAGE_MIN_ADDRESS ) {
rsi_dbg ( ERR_ZONE ,
" %s: Fw image Flash Start Address is less than 64K \n " ,
__func__ ) ;
return - EINVAL ;
}
if ( flash_start_address % FLASH_SECTOR_SIZE ) {
rsi_dbg ( ERR_ZONE ,
" %s: Flash Start Address is not multiple of 4K \n " ,
__func__ ) ;
return - EINVAL ;
}
if ( ( flash_start_address + content_size ) > adapter - > flash_capacity ) {
rsi_dbg ( ERR_ZONE ,
" %s: Flash Content will cross max flash size \n " ,
__func__ ) ;
return - EINVAL ;
}
temp_content_size = content_size ;
num_flash = content_size / FLASH_WRITE_CHUNK_SIZE ;
rsi_dbg ( INFO_ZONE , " content_size: %d, num_flash: %d \n " ,
content_size , num_flash ) ;
for ( index = 0 ; index < = num_flash ; index + + ) {
rsi_dbg ( INFO_ZONE , " flash index: %d \n " , index ) ;
if ( index ! = num_flash ) {
content_size = FLASH_WRITE_CHUNK_SIZE ;
rsi_dbg ( INFO_ZONE , " QSPI content_size:%d \n " ,
content_size ) ;
} else {
content_size =
temp_content_size % FLASH_WRITE_CHUNK_SIZE ;
rsi_dbg ( INFO_ZONE ,
" Writing last sector content_size:%d \n " ,
content_size ) ;
if ( ! content_size ) {
rsi_dbg ( INFO_ZONE , " instruction size zero \n " ) ;
break ;
}
}
if ( index % 2 )
cmd = PING_WRITE ;
else
cmd = PONG_WRITE ;
status = ping_pong_write ( adapter , cmd , flash_content ,
content_size ) ;
if ( status ) {
rsi_dbg ( ERR_ZONE , " %s: Unable to load %d block \n " ,
__func__ , index ) ;
return status ;
}
rsi_dbg ( INFO_ZONE ,
" %s: Successfully loaded %d instructions \n " ,
__func__ , index ) ;
flash_content + = content_size ;
}
status = bl_cmd ( adapter , EOF_REACHED , FW_LOADING_SUCCESSFUL ,
" EOF_REACHED " ) ;
2019-11-28 18:22:01 +01:00
if ( status )
2017-05-16 15:31:16 +05:30
return status ;
2019-11-28 18:22:01 +01:00
2017-05-16 15:31:16 +05:30
rsi_dbg ( INFO_ZONE , " FW loading is done and FW is running.. \n " ) ;
return 0 ;
}
2019-04-03 09:43:03 +05:30
static int rsi_hal_prepare_fwload ( struct rsi_hw * adapter )
2017-05-16 15:31:16 +05:30
{
struct rsi_host_intf_ops * hif_ops = adapter - > host_intf_ops ;
2019-04-03 09:43:03 +05:30
u32 regout_val = 0 ;
2017-05-16 15:31:16 +05:30
int status ;
bl_start_cmd_timer ( adapter , BL_CMD_TIMEOUT ) ;
while ( ! adapter - > blcmd_timer_expired ) {
status = hif_ops - > master_reg_read ( adapter , SWBL_REGOUT ,
2019-04-03 09:43:03 +05:30
& regout_val ,
RSI_COMMON_REG_SIZE ) ;
2017-05-16 15:31:16 +05:30
if ( status < 0 ) {
2019-11-28 18:22:01 +01:00
bl_stop_cmd_timer ( adapter ) ;
2017-05-16 15:31:16 +05:30
rsi_dbg ( ERR_ZONE ,
" %s: REGOUT read failed \n " , __func__ ) ;
return status ;
}
mdelay ( 1 ) ;
if ( ( regout_val > > 8 ) = = REGOUT_VALID )
break ;
}
if ( adapter - > blcmd_timer_expired ) {
rsi_dbg ( ERR_ZONE , " %s: REGOUT read timedout \n " , __func__ ) ;
rsi_dbg ( ERR_ZONE ,
" %s: Soft boot loader not present \n " , __func__ ) ;
return - ETIMEDOUT ;
}
bl_stop_cmd_timer ( adapter ) ;
rsi_dbg ( INFO_ZONE , " Received Board Version Number: %x \n " ,
( regout_val & 0xff ) ) ;
status = hif_ops - > master_reg_write ( adapter , SWBL_REGOUT ,
2019-04-03 09:43:03 +05:30
( REGOUT_INVALID |
REGOUT_INVALID < < 8 ) ,
RSI_COMMON_REG_SIZE ) ;
if ( status < 0 )
2017-05-16 15:31:16 +05:30
rsi_dbg ( ERR_ZONE , " %s: REGOUT writing failed.. \n " , __func__ ) ;
2019-04-03 09:43:03 +05:30
else
rsi_dbg ( INFO_ZONE ,
" ===> Device is ready to load firmware <=== \n " ) ;
return status ;
}
static int rsi_load_9113_firmware ( struct rsi_hw * adapter )
{
struct rsi_common * common = adapter - > priv ;
const struct firmware * fw_entry = NULL ;
u32 content_size ;
u16 tmp_regout_val = 0 ;
struct ta_metadata * metadata_p ;
int status ;
2017-05-16 15:31:16 +05:30
status = bl_cmd ( adapter , CONFIG_AUTO_READ_MODE , CMD_PASS ,
" AUTO_READ_CMD " ) ;
if ( status < 0 )
return status ;
adapter - > flash_capacity = read_flash_capacity ( adapter ) ;
if ( adapter - > flash_capacity < = 0 ) {
rsi_dbg ( ERR_ZONE ,
" %s: Unable to read flash size from EEPROM \n " ,
__func__ ) ;
return - EINVAL ;
}
metadata_p = & metadata_flash_content [ adapter - > priv - > coex_mode ] ;
rsi_dbg ( INIT_ZONE , " %s: Loading file %s \n " , __func__ , metadata_p - > name ) ;
adapter - > fw_file_name = metadata_p - > name ;
status = request_firmware ( & fw_entry , metadata_p - > name , adapter - > device ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE , " %s: Failed to open file %s \n " ,
__func__ , metadata_p - > name ) ;
return status ;
}
content_size = fw_entry - > size ;
rsi_dbg ( INFO_ZONE , " FW Length = %d bytes \n " , content_size ) ;
2017-09-21 18:20:34 +05:30
/* Get the firmware version */
common - > lmac_ver . ver . info . fw_ver [ 0 ] =
2019-04-03 09:43:03 +05:30
fw_entry - > data [ LMAC_VER_OFFSET_9113 ] & 0xFF ;
2017-09-21 18:20:34 +05:30
common - > lmac_ver . ver . info . fw_ver [ 1 ] =
2019-04-03 09:43:03 +05:30
fw_entry - > data [ LMAC_VER_OFFSET_9113 + 1 ] & 0xFF ;
common - > lmac_ver . major =
fw_entry - > data [ LMAC_VER_OFFSET_9113 + 2 ] & 0xFF ;
2017-09-21 18:20:34 +05:30
common - > lmac_ver . release_num =
2019-04-03 09:43:03 +05:30
fw_entry - > data [ LMAC_VER_OFFSET_9113 + 3 ] & 0xFF ;
common - > lmac_ver . minor =
fw_entry - > data [ LMAC_VER_OFFSET_9113 + 4 ] & 0xFF ;
2017-09-21 18:20:34 +05:30
common - > lmac_ver . patch_num = 0 ;
rsi_print_version ( common ) ;
2018-07-16 19:09:33 +05:30
status = bl_write_header ( adapter , ( u8 * ) fw_entry - > data , content_size ) ;
2017-05-16 15:31:16 +05:30
if ( status ) {
rsi_dbg ( ERR_ZONE ,
" %s: RPS Image header loading failed \n " ,
__func__ ) ;
goto fail ;
}
bl_start_cmd_timer ( adapter , BL_CMD_TIMEOUT ) ;
status = bl_write_cmd ( adapter , CHECK_CRC , CMD_PASS , & tmp_regout_val ) ;
if ( status ) {
bl_stop_cmd_timer ( adapter ) ;
rsi_dbg ( ERR_ZONE ,
" %s: CHECK_CRC Command writing failed.. \n " ,
__func__ ) ;
if ( ( tmp_regout_val & 0xff ) = = CMD_FAIL ) {
rsi_dbg ( ERR_ZONE ,
" CRC Fail.. Proceeding to Upgrade mode \n " ) ;
goto fw_upgrade ;
}
}
bl_stop_cmd_timer ( adapter ) ;
status = bl_cmd ( adapter , POLLING_MODE , CMD_PASS , " POLLING_MODE " ) ;
if ( status )
goto fail ;
load_image_cmd :
status = bl_cmd ( adapter , LOAD_HOSTED_FW , LOADING_INITIATED ,
" LOAD_HOSTED_FW " ) ;
if ( status )
goto fail ;
rsi_dbg ( INFO_ZONE , " Load Image command passed.. \n " ) ;
goto success ;
fw_upgrade :
status = bl_cmd ( adapter , BURN_HOSTED_FW , SEND_RPS_FILE , " FW_UPGRADE " ) ;
if ( status )
goto fail ;
rsi_dbg ( INFO_ZONE , " Burn Command Pass.. Upgrading the firmware \n " ) ;
2018-07-16 19:09:33 +05:30
status = auto_fw_upgrade ( adapter , ( u8 * ) fw_entry - > data , content_size ) ;
2017-05-16 15:31:16 +05:30
if ( status = = 0 ) {
rsi_dbg ( ERR_ZONE , " Firmware upgradation Done \n " ) ;
goto load_image_cmd ;
}
rsi_dbg ( ERR_ZONE , " Firmware upgrade failed \n " ) ;
status = bl_cmd ( adapter , CONFIG_AUTO_READ_MODE , CMD_PASS ,
" AUTO_READ_MODE " ) ;
if ( status )
goto fail ;
success :
rsi_dbg ( ERR_ZONE , " ***** Firmware Loading successful ***** \n " ) ;
release_firmware ( fw_entry ) ;
return 0 ;
fail :
rsi_dbg ( ERR_ZONE , " ##### Firmware loading failed ##### \n " ) ;
release_firmware ( fw_entry ) ;
return status ;
}
2019-04-03 09:43:04 +05:30
static int rsi_load_9116_firmware ( struct rsi_hw * adapter )
{
struct rsi_common * common = adapter - > priv ;
struct rsi_host_intf_ops * hif_ops = adapter - > host_intf_ops ;
const struct firmware * fw_entry ;
struct ta_metadata * metadata_p ;
u8 * ta_firmware , * fw_p ;
struct bootload_ds bootload_ds ;
u32 instructions_sz , base_address ;
u16 block_size = adapter - > block_size ;
u32 dest , len ;
int status , cnt ;
rsi_dbg ( INIT_ZONE , " ***** Load 9116 TA Instructions ***** \n " ) ;
if ( adapter - > rsi_host_intf = = RSI_HOST_INTF_USB ) {
status = bl_cmd ( adapter , POLLING_MODE , CMD_PASS ,
" POLLING_MODE " ) ;
if ( status < 0 )
return status ;
}
status = hif_ops - > master_reg_write ( adapter , MEM_ACCESS_CTRL_FROM_HOST ,
RAM_384K_ACCESS_FROM_TA ,
RSI_9116_REG_SIZE ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE , " %s: Unable to access full RAM memory \n " ,
__func__ ) ;
return status ;
}
metadata_p = & metadata [ adapter - > priv - > coex_mode ] ;
rsi_dbg ( INIT_ZONE , " %s: loading file %s \n " , __func__ , metadata_p - > name ) ;
status = request_firmware ( & fw_entry , metadata_p - > name , adapter - > device ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE , " %s: Failed to open file %s \n " ,
__func__ , metadata_p - > name ) ;
return status ;
}
ta_firmware = kmemdup ( fw_entry - > data , fw_entry - > size , GFP_KERNEL ) ;
if ( ! ta_firmware )
goto fail_release_fw ;
fw_p = ta_firmware ;
instructions_sz = fw_entry - > size ;
rsi_dbg ( INFO_ZONE , " FW Length = %d bytes \n " , instructions_sz ) ;
common - > lmac_ver . major = ta_firmware [ LMAC_VER_OFFSET_9116 ] ;
common - > lmac_ver . minor = ta_firmware [ LMAC_VER_OFFSET_9116 + 1 ] ;
common - > lmac_ver . release_num = ta_firmware [ LMAC_VER_OFFSET_9116 + 2 ] ;
common - > lmac_ver . patch_num = ta_firmware [ LMAC_VER_OFFSET_9116 + 3 ] ;
common - > lmac_ver . ver . info . fw_ver [ 0 ] =
ta_firmware [ LMAC_VER_OFFSET_9116 + 4 ] ;
if ( instructions_sz % FW_ALIGN_SIZE )
instructions_sz + =
( FW_ALIGN_SIZE - ( instructions_sz % FW_ALIGN_SIZE ) ) ;
rsi_dbg ( INFO_ZONE , " instructions_sz : %d \n " , instructions_sz ) ;
if ( * ( u16 * ) fw_p = = RSI_9116_FW_MAGIC_WORD ) {
memcpy ( & bootload_ds , fw_p , sizeof ( struct bootload_ds ) ) ;
fw_p + = le16_to_cpu ( bootload_ds . offset ) ;
rsi_dbg ( INFO_ZONE , " FW start = %x \n " , * ( u32 * ) fw_p ) ;
cnt = 0 ;
do {
rsi_dbg ( ERR_ZONE , " %s: Loading chunk %d \n " ,
__func__ , cnt ) ;
dest = le32_to_cpu ( bootload_ds . bl_entry [ cnt ] . dst_addr ) ;
len = le32_to_cpu ( bootload_ds . bl_entry [ cnt ] . control ) &
RSI_BL_CTRL_LEN_MASK ;
rsi_dbg ( INFO_ZONE , " length %d destination %x \n " ,
len , dest ) ;
status = hif_ops - > load_data_master_write ( adapter , dest ,
len ,
block_size ,
fw_p ) ;
if ( status < 0 ) {
rsi_dbg ( ERR_ZONE ,
" Failed to load chunk %d \n " , cnt ) ;
break ;
}
fw_p + = len ;
if ( le32_to_cpu ( bootload_ds . bl_entry [ cnt ] . control ) &
RSI_BL_CTRL_LAST_ENTRY )
break ;
cnt + + ;
} while ( 1 ) ;
} else {
base_address = metadata_p - > address ;
status = hif_ops - > load_data_master_write ( adapter ,
base_address ,
instructions_sz ,
block_size ,
ta_firmware ) ;
}
if ( status ) {
rsi_dbg ( ERR_ZONE ,
" %s: Unable to load %s blk \n " ,
__func__ , metadata_p - > name ) ;
goto fail_free_fw ;
}
rsi_dbg ( INIT_ZONE , " %s: Successfully loaded %s instructions \n " ,
__func__ , metadata_p - > name ) ;
if ( adapter - > rsi_host_intf = = RSI_HOST_INTF_SDIO ) {
if ( hif_ops - > ta_reset ( adapter ) )
rsi_dbg ( ERR_ZONE , " Unable to put ta in reset \n " ) ;
} else {
if ( bl_cmd ( adapter , JUMP_TO_ZERO_PC ,
CMD_PASS , " JUMP_TO_ZERO " ) < 0 )
rsi_dbg ( INFO_ZONE , " Jump to zero command failed \n " ) ;
else
rsi_dbg ( INFO_ZONE , " Jump to zero command successful \n " ) ;
}
fail_free_fw :
kfree ( ta_firmware ) ;
fail_release_fw :
release_firmware ( fw_entry ) ;
return status ;
}
2017-05-16 15:31:16 +05:30
int rsi_hal_device_init ( struct rsi_hw * adapter )
{
struct rsi_common * common = adapter - > priv ;
2019-04-03 09:43:03 +05:30
int status ;
2017-05-16 15:31:16 +05:30
switch ( adapter - > device_model ) {
case RSI_DEV_9113 :
2019-04-03 09:43:03 +05:30
status = rsi_hal_prepare_fwload ( adapter ) ;
if ( status < 0 )
return status ;
if ( rsi_load_9113_firmware ( adapter ) ) {
2017-05-16 15:31:16 +05:30
rsi_dbg ( ERR_ZONE ,
" %s: Failed to load TA instructions \n " ,
__func__ ) ;
return - EINVAL ;
}
break ;
2019-04-03 09:43:04 +05:30
case RSI_DEV_9116 :
status = rsi_hal_prepare_fwload ( adapter ) ;
if ( status < 0 )
return status ;
if ( rsi_load_9116_firmware ( adapter ) ) {
rsi_dbg ( ERR_ZONE ,
" %s: Failed to load firmware to 9116 device \n " ,
__func__ ) ;
return - EINVAL ;
}
break ;
2017-05-16 15:31:16 +05:30
default :
return - EINVAL ;
}
2017-06-16 20:05:38 +05:30
common - > fsm_state = FSM_CARD_NOT_READY ;
2017-05-16 15:31:16 +05:30
return 0 ;
}
EXPORT_SYMBOL_GPL ( rsi_hal_device_init ) ;