2012-12-21 01:13:19 +04:00
/*
2014-08-06 11:31:51 +04:00
* Copyright ( c ) 2012 - 2014 Qualcomm Atheros , Inc .
2012-12-21 01:13:19 +04:00
*
* 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 .
*/
# include <linux/moduleparam.h>
# include <linux/if_arp.h>
2014-02-27 18:20:53 +04:00
# include <linux/etherdevice.h>
2012-12-21 01:13:19 +04:00
# include "wil6210.h"
2014-02-27 18:20:44 +04:00
# include "txrx.h"
2014-09-10 17:34:38 +04:00
# include "wmi.h"
# define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
# define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
2012-12-21 01:13:19 +04:00
2014-10-01 16:05:24 +04:00
bool no_fw_recovery ;
2014-03-17 17:34:19 +04:00
module_param ( no_fw_recovery , bool , S_IRUGO | S_IWUSR ) ;
2014-10-01 16:05:24 +04:00
MODULE_PARM_DESC ( no_fw_recovery , " disable automatic FW error recovery " ) ;
2014-03-17 17:34:19 +04:00
2014-09-10 17:34:30 +04:00
static bool no_fw_load = true ;
module_param ( no_fw_load , bool , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( no_fw_load , " do not download FW, use one in on-card flash. " ) ;
2014-09-22 16:31:41 +04:00
static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT ;
module_param ( itr_trsh , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( itr_trsh , " Interrupt moderation threshold, usecs. " ) ;
2014-10-28 17:51:27 +03:00
/* We allow allocation of more than 1 page buffers to support large packets.
* It is suboptimal behavior performance wise in case MTU above page size .
*/
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN ;
static int mtu_max_set ( const char * val , const struct kernel_param * kp )
{
int ret ;
/* sets mtu_max directly. no need to restore it in case of
* illegal value since we assume this will fail insmod
*/
ret = param_set_uint ( val , kp ) ;
if ( ret )
return ret ;
if ( mtu_max < 68 | | mtu_max > IEEE80211_MAX_DATA_LEN_DMG )
ret = - EINVAL ;
return ret ;
}
static struct kernel_param_ops mtu_max_ops = {
. set = mtu_max_set ,
. get = param_get_uint ,
} ;
module_param_cb ( mtu_max , & mtu_max_ops , & mtu_max , S_IRUGO ) ;
MODULE_PARM_DESC ( mtu_max , " Max MTU value. " ) ;
2014-12-01 16:35:02 +03:00
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT ;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT ;
static int ring_order_set ( const char * val , const struct kernel_param * kp )
{
int ret ;
uint x ;
ret = kstrtouint ( val , 0 , & x ) ;
if ( ret )
return ret ;
if ( ( x < WIL_RING_SIZE_ORDER_MIN ) | | ( x > WIL_RING_SIZE_ORDER_MAX ) )
return - EINVAL ;
* ( ( uint * ) kp - > arg ) = x ;
return 0 ;
}
static struct kernel_param_ops ring_order_ops = {
. set = ring_order_set ,
. get = param_get_uint ,
} ;
module_param_cb ( rx_ring_order , & ring_order_ops , & rx_ring_order , S_IRUGO ) ;
MODULE_PARM_DESC ( rx_ring_order , " Rx ring order; size = 1 << order " ) ;
module_param_cb ( tx_ring_order , & ring_order_ops , & tx_ring_order , S_IRUGO ) ;
MODULE_PARM_DESC ( tx_ring_order , " Tx ring order; size = 1 << order " ) ;
2014-08-06 11:31:53 +04:00
# define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
# define RST_COUNT (1 + 1000 / RST_DELAY) /* round up to be above 1 sec total */
2012-12-21 01:13:19 +04:00
/*
* Due to a hardware issue ,
* one has to read / write to / from NIC in 32 - bit chunks ;
* regular memcpy_fromio and siblings will
* not work on 64 - bit platform - it uses 64 - bit transactions
*
* Force 32 - bit transactions to enable NIC on 64 - bit platforms
*
* To avoid byte swap on big endian host , __raw_ { read | write } l
* should be used - { read | write } l would swap bytes to provide
* little endian on PCI value in host endianness .
*/
void wil_memcpy_fromio_32 ( void * dst , const volatile void __iomem * src ,
size_t count )
{
u32 * d = dst ;
const volatile u32 __iomem * s = src ;
/* size_t is unsigned, if (count%4 != 0) it will wrap */
for ( count + = 4 ; count > 4 ; count - = 4 )
* d + + = __raw_readl ( s + + ) ;
}
void wil_memcpy_toio_32 ( volatile void __iomem * dst , const void * src ,
size_t count )
{
volatile u32 __iomem * d = dst ;
const u32 * s = src ;
for ( count + = 4 ; count > 4 ; count - = 4 )
__raw_writel ( * s + + , d + + ) ;
}
2014-10-28 17:50:08 +03:00
static void wil_disconnect_cid ( struct wil6210_priv * wil , int cid ,
2014-12-01 16:33:15 +03:00
u16 reason_code , bool from_event )
2014-02-27 18:20:50 +04:00
{
uint i ;
2014-06-16 20:37:16 +04:00
struct net_device * ndev = wil_to_ndev ( wil ) ;
struct wireless_dev * wdev = wil - > wdev ;
2014-02-27 18:20:50 +04:00
struct wil_sta_info * sta = & wil - > sta [ cid ] ;
2014-09-10 17:34:34 +04:00
2014-06-16 20:37:16 +04:00
wil_dbg_misc ( wil , " %s(CID %d, status %d) \n " , __func__ , cid ,
sta - > status ) ;
2014-02-27 18:20:54 +04:00
2014-03-17 17:34:06 +04:00
sta - > data_port_open = false ;
2014-02-27 18:20:54 +04:00
if ( sta - > status ! = wil_sta_unused ) {
2014-10-28 17:50:08 +03:00
if ( ! from_event )
2014-12-01 16:33:15 +03:00
wmi_disconnect_sta ( wil , sta - > addr , reason_code ) ;
2014-10-28 17:50:08 +03:00
2014-06-16 20:37:16 +04:00
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_P2P_GO :
/* AP-like interface */
cfg80211_del_sta ( ndev , sta - > addr , GFP_KERNEL ) ;
break ;
default :
break ;
}
2014-02-27 18:20:54 +04:00
sta - > status = wil_sta_unused ;
}
2014-02-27 18:20:50 +04:00
for ( i = 0 ; i < WIL_STA_TID_NUM ; i + + ) {
2014-09-10 17:34:42 +04:00
struct wil_tid_ampdu_rx * r ;
unsigned long flags ;
spin_lock_irqsave ( & sta - > tid_rx_lock , flags ) ;
r = sta - > tid_rx [ i ] ;
2014-02-27 18:20:50 +04:00
sta - > tid_rx [ i ] = NULL ;
wil_tid_ampdu_rx_free ( wil , r ) ;
2014-09-10 17:34:42 +04:00
spin_unlock_irqrestore ( & sta - > tid_rx_lock , flags ) ;
2014-02-27 18:20:50 +04:00
}
for ( i = 0 ; i < ARRAY_SIZE ( wil - > vring_tx ) ; i + + ) {
if ( wil - > vring2cid_tid [ i ] [ 0 ] = = cid )
wil_vring_fini_tx ( wil , i ) ;
}
memset ( & sta - > stats , 0 , sizeof ( sta - > stats ) ) ;
}
2014-10-28 17:50:08 +03:00
static void _wil6210_disconnect ( struct wil6210_priv * wil , const u8 * bssid ,
2014-12-01 16:33:15 +03:00
u16 reason_code , bool from_event )
2012-12-21 01:13:19 +04:00
{
2014-02-27 18:20:50 +04:00
int cid = - ENOENT ;
2012-12-21 01:13:19 +04:00
struct net_device * ndev = wil_to_ndev ( wil ) ;
2014-02-27 18:20:50 +04:00
struct wireless_dev * wdev = wil - > wdev ;
might_sleep ( ) ;
if ( bssid ) {
cid = wil_find_cid ( wil , bssid ) ;
wil_dbg_misc ( wil , " %s(%pM, CID %d) \n " , __func__ , bssid , cid ) ;
} else {
wil_dbg_misc ( wil , " %s(all) \n " , __func__ ) ;
2014-02-27 18:20:44 +04:00
}
2014-02-27 18:20:50 +04:00
if ( cid > = 0 ) /* disconnect 1 peer */
2014-12-01 16:33:15 +03:00
wil_disconnect_cid ( wil , cid , reason_code , from_event ) ;
2014-02-27 18:20:50 +04:00
else /* disconnect all */
for ( cid = 0 ; cid < WIL6210_MAX_CID ; cid + + )
2014-12-01 16:33:15 +03:00
wil_disconnect_cid ( wil , cid , reason_code , from_event ) ;
2014-02-27 18:20:50 +04:00
/* link state */
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_P2P_CLIENT :
wil_link_off ( wil ) ;
if ( test_bit ( wil_status_fwconnected , & wil - > status ) ) {
clear_bit ( wil_status_fwconnected , & wil - > status ) ;
2014-12-01 16:33:15 +03:00
cfg80211_disconnected ( ndev , reason_code ,
2014-02-27 18:20:50 +04:00
NULL , 0 , GFP_KERNEL ) ;
} else if ( test_bit ( wil_status_fwconnecting , & wil - > status ) ) {
cfg80211_connect_result ( ndev , bssid , NULL , 0 , NULL , 0 ,
WLAN_STATUS_UNSPECIFIED_FAILURE ,
GFP_KERNEL ) ;
}
clear_bit ( wil_status_fwconnecting , & wil - > status ) ;
break ;
default :
break ;
2012-12-21 01:13:19 +04:00
}
}
static void wil_disconnect_worker ( struct work_struct * work )
{
struct wil6210_priv * wil = container_of ( work ,
struct wil6210_priv , disconnect_worker ) ;
2014-03-17 17:34:25 +04:00
mutex_lock ( & wil - > mutex ) ;
2014-12-01 16:33:15 +03:00
_wil6210_disconnect ( wil , NULL , WLAN_REASON_UNSPECIFIED , false ) ;
2014-03-17 17:34:25 +04:00
mutex_unlock ( & wil - > mutex ) ;
2012-12-21 01:13:19 +04:00
}
static void wil_connect_timer_fn ( ulong x )
{
struct wil6210_priv * wil = ( void * ) x ;
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " Connect timeout \n " ) ;
2012-12-21 01:13:19 +04:00
/* reschedule to thread context - disconnect won't
* run from atomic context
*/
schedule_work ( & wil - > disconnect_worker ) ;
}
2014-05-27 15:45:48 +04:00
static void wil_scan_timer_fn ( ulong x )
{
struct wil6210_priv * wil = ( void * ) x ;
clear_bit ( wil_status_fwready , & wil - > status ) ;
wil_err ( wil , " Scan timeout detected, start fw error recovery \n " ) ;
2014-12-01 16:33:17 +03:00
wil - > recovery_state = fw_recovery_pending ;
2014-05-27 15:45:48 +04:00
schedule_work ( & wil - > fw_error_worker ) ;
}
2014-10-01 16:05:24 +04:00
static int wil_wait_for_recovery ( struct wil6210_priv * wil )
{
if ( wait_event_interruptible ( wil - > wq , wil - > recovery_state ! =
fw_recovery_pending ) ) {
wil_err ( wil , " Interrupt, canceling recovery \n " ) ;
return - ERESTARTSYS ;
}
if ( wil - > recovery_state ! = fw_recovery_running ) {
wil_info ( wil , " Recovery cancelled \n " ) ;
return - EINTR ;
}
wil_info ( wil , " Proceed with recovery \n " ) ;
return 0 ;
}
void wil_set_recovery_state ( struct wil6210_priv * wil , int state )
{
wil_dbg_misc ( wil , " %s(%d -> %d) \n " , __func__ ,
wil - > recovery_state , state ) ;
wil - > recovery_state = state ;
wake_up_interruptible ( & wil - > wq ) ;
}
2014-03-17 17:34:19 +04:00
static void wil_fw_error_worker ( struct work_struct * work )
{
2014-10-01 16:05:24 +04:00
struct wil6210_priv * wil = container_of ( work , struct wil6210_priv ,
fw_error_worker ) ;
2014-03-17 17:34:19 +04:00
struct wireless_dev * wdev = wil - > wdev ;
wil_dbg_misc ( wil , " fw error worker \n " ) ;
2014-10-28 17:50:06 +03:00
if ( ! netif_running ( wil_to_ndev ( wil ) ) ) {
wil_info ( wil , " No recovery - interface is down \n " ) ;
return ;
}
2014-05-27 15:45:45 +04:00
/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
* passed since last recovery attempt
*/
if ( time_is_after_jiffies ( wil - > last_fw_recovery +
WIL6210_FW_RECOVERY_TO ) )
wil - > recovery_count + + ;
else
wil - > recovery_count = 1 ; /* fw was alive for a long time */
if ( wil - > recovery_count > WIL6210_FW_RECOVERY_RETRIES ) {
wil_err ( wil , " too many recovery attempts (%d), giving up \n " ,
wil - > recovery_count ) ;
return ;
}
wil - > last_fw_recovery = jiffies ;
2014-03-17 17:34:21 +04:00
mutex_lock ( & wil - > mutex ) ;
2014-03-17 17:34:19 +04:00
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_STATION :
case NL80211_IFTYPE_P2P_CLIENT :
case NL80211_IFTYPE_MONITOR :
2014-10-01 16:05:24 +04:00
wil_info ( wil , " fw error recovery requested (try %d)... \n " ,
2014-05-27 15:45:45 +04:00
wil - > recovery_count ) ;
2014-10-01 16:05:24 +04:00
if ( ! no_fw_recovery )
wil - > recovery_state = fw_recovery_running ;
if ( 0 ! = wil_wait_for_recovery ( wil ) )
break ;
2014-09-10 17:34:50 +04:00
__wil_down ( wil ) ;
__wil_up ( wil ) ;
2014-03-17 17:34:19 +04:00
break ;
case NL80211_IFTYPE_AP :
case NL80211_IFTYPE_P2P_GO :
2014-10-28 17:50:09 +03:00
wil_info ( wil , " No recovery for AP-like interface \n " ) ;
2014-03-17 17:34:19 +04:00
/* recovery in these modes is done by upper layers */
break ;
default :
2014-10-28 17:50:09 +03:00
wil_err ( wil , " No recovery - unknown interface type %d \n " ,
wdev - > iftype ) ;
2014-03-17 17:34:19 +04:00
break ;
}
2014-03-17 17:34:21 +04:00
mutex_unlock ( & wil - > mutex ) ;
2014-03-17 17:34:19 +04:00
}
2014-02-27 18:20:45 +04:00
static int wil_find_free_vring ( struct wil6210_priv * wil )
{
int i ;
2014-09-10 17:34:34 +04:00
2014-02-27 18:20:45 +04:00
for ( i = 0 ; i < WIL6210_MAX_TX_RINGS ; i + + ) {
if ( ! wil - > vring_tx [ i ] . va )
return i ;
}
return - EINVAL ;
}
2013-03-13 16:12:43 +04:00
static void wil_connect_worker ( struct work_struct * work )
{
int rc ;
struct wil6210_priv * wil = container_of ( work , struct wil6210_priv ,
connect_worker ) ;
int cid = wil - > pending_connect_cid ;
2014-02-27 18:20:45 +04:00
int ringid = wil_find_free_vring ( wil ) ;
2013-03-13 16:12:43 +04:00
if ( cid < 0 ) {
wil_err ( wil , " No connection pending \n " ) ;
return ;
}
wil_dbg_wmi ( wil , " Configure for connection CID %d \n " , cid ) ;
2014-12-01 16:35:02 +03:00
rc = wil_vring_init_tx ( wil , ringid , 1 < < tx_ring_order , cid , 0 ) ;
2013-03-13 16:12:43 +04:00
wil - > pending_connect_cid = - 1 ;
2014-02-27 18:20:43 +04:00
if ( rc = = 0 ) {
wil - > sta [ cid ] . status = wil_sta_connected ;
2013-03-13 16:12:43 +04:00
wil_link_on ( wil ) ;
2014-02-27 18:20:43 +04:00
} else {
wil - > sta [ cid ] . status = wil_sta_unused ;
}
2013-03-13 16:12:43 +04:00
}
2012-12-21 01:13:19 +04:00
int wil_priv_init ( struct wil6210_priv * wil )
{
2014-09-10 17:34:42 +04:00
uint i ;
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2012-12-21 01:13:19 +04:00
2014-02-27 18:20:43 +04:00
memset ( wil - > sta , 0 , sizeof ( wil - > sta ) ) ;
2014-09-10 17:34:42 +04:00
for ( i = 0 ; i < WIL6210_MAX_CID ; i + + )
spin_lock_init ( & wil - > sta [ i ] . tid_rx_lock ) ;
2014-02-27 18:20:43 +04:00
2012-12-21 01:13:19 +04:00
mutex_init ( & wil - > mutex ) ;
mutex_init ( & wil - > wmi_mutex ) ;
init_completion ( & wil - > wmi_ready ) ;
2014-09-10 17:34:46 +04:00
init_completion ( & wil - > wmi_call ) ;
2012-12-21 01:13:19 +04:00
wil - > pending_connect_cid = - 1 ;
setup_timer ( & wil - > connect_timer , wil_connect_timer_fn , ( ulong ) wil ) ;
2014-05-27 15:45:48 +04:00
setup_timer ( & wil - > scan_timer , wil_scan_timer_fn , ( ulong ) wil ) ;
2012-12-21 01:13:19 +04:00
2013-03-13 16:12:43 +04:00
INIT_WORK ( & wil - > connect_worker , wil_connect_worker ) ;
2012-12-21 01:13:19 +04:00
INIT_WORK ( & wil - > disconnect_worker , wil_disconnect_worker ) ;
INIT_WORK ( & wil - > wmi_event_worker , wmi_event_worker ) ;
2014-03-17 17:34:19 +04:00
INIT_WORK ( & wil - > fw_error_worker , wil_fw_error_worker ) ;
2012-12-21 01:13:19 +04:00
INIT_LIST_HEAD ( & wil - > pending_wmi_ev ) ;
spin_lock_init ( & wil - > wmi_ev_lock ) ;
2014-10-01 16:05:24 +04:00
init_waitqueue_head ( & wil - > wq ) ;
2012-12-21 01:13:19 +04:00
wil - > wmi_wq = create_singlethread_workqueue ( WIL_NAME " _wmi " ) ;
if ( ! wil - > wmi_wq )
return - EAGAIN ;
wil - > wmi_wq_conn = create_singlethread_workqueue ( WIL_NAME " _connect " ) ;
if ( ! wil - > wmi_wq_conn ) {
destroy_workqueue ( wil - > wmi_wq ) ;
return - EAGAIN ;
}
2014-05-27 15:45:45 +04:00
wil - > last_fw_recovery = jiffies ;
2014-09-22 16:31:41 +04:00
wil - > itr_trsh = itr_trsh ;
2014-05-27 15:45:45 +04:00
2012-12-21 01:13:19 +04:00
return 0 ;
}
2014-10-28 17:50:08 +03:00
/**
* wil6210_disconnect - disconnect one connection
* @ wil : driver context
* @ bssid : peer to disconnect , NULL to disconnect all
2014-12-01 16:33:15 +03:00
* @ reason_code : Reason code for the Disassociation frame
2014-10-28 17:50:08 +03:00
* @ from_event : whether is invoked from FW event handler
*
* Disconnect and release associated resources . If invoked not from the
* FW event handler , issue WMI command ( s ) to trigger MAC disconnect .
*/
void wil6210_disconnect ( struct wil6210_priv * wil , const u8 * bssid ,
2014-12-01 16:33:15 +03:00
u16 reason_code , bool from_event )
2012-12-21 01:13:19 +04:00
{
2014-09-10 17:34:36 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2012-12-21 01:13:19 +04:00
del_timer_sync ( & wil - > connect_timer ) ;
2014-12-01 16:33:15 +03:00
_wil6210_disconnect ( wil , bssid , reason_code , from_event ) ;
2012-12-21 01:13:19 +04:00
}
void wil_priv_deinit ( struct wil6210_priv * wil )
{
2014-09-10 17:34:36 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2014-10-01 16:05:24 +04:00
wil_set_recovery_state ( wil , fw_recovery_idle ) ;
2014-05-27 15:45:48 +04:00
del_timer_sync ( & wil - > scan_timer ) ;
2012-12-21 01:13:19 +04:00
cancel_work_sync ( & wil - > disconnect_worker ) ;
2014-03-17 17:34:19 +04:00
cancel_work_sync ( & wil - > fw_error_worker ) ;
2014-03-17 17:34:25 +04:00
mutex_lock ( & wil - > mutex ) ;
2014-12-01 16:33:15 +03:00
wil6210_disconnect ( wil , NULL , WLAN_REASON_DEAUTH_LEAVING , false ) ;
2014-03-17 17:34:25 +04:00
mutex_unlock ( & wil - > mutex ) ;
2012-12-21 01:13:19 +04:00
wmi_event_flush ( wil ) ;
destroy_workqueue ( wil - > wmi_wq_conn ) ;
destroy_workqueue ( wil - > wmi_wq ) ;
}
2014-09-10 17:34:30 +04:00
/* target operations */
/* register read */
# define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write. wmb() to make sure it is completed */
# define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
/* register set = read, OR, write */
# define S(a, v) W(a, R(a) | v)
/* register clear = read, AND with inverted, write */
# define C(a, v) W(a, R(a) & ~v)
static inline void wil_halt_cpu ( struct wil6210_priv * wil )
{
W ( RGF_USER_USER_CPU_0 , BIT_USER_USER_CPU_MAN_RST ) ;
W ( RGF_USER_MAC_CPU_0 , BIT_USER_MAC_CPU_MAN_RST ) ;
}
static inline void wil_release_cpu ( struct wil6210_priv * wil )
{
/* Start CPU */
W ( RGF_USER_USER_CPU_0 , 1 ) ;
}
2014-08-06 11:31:52 +04:00
static int wil_target_reset ( struct wil6210_priv * wil )
2012-12-21 01:13:19 +04:00
{
2014-03-17 17:34:12 +04:00
int delay = 0 ;
2014-10-28 17:50:07 +03:00
u32 x ;
2014-03-17 17:34:10 +04:00
u32 rev_id ;
2014-07-14 10:49:37 +04:00
bool is_sparrow = ( wil - > board - > board = = WIL_BOARD_SPARROW ) ;
2014-03-17 17:34:10 +04:00
2014-07-14 10:49:37 +04:00
wil_dbg_misc ( wil , " Resetting \" %s \" ... \n " , wil - > board - > name ) ;
2012-12-21 01:13:19 +04:00
2014-03-17 17:34:14 +04:00
wil - > hw_version = R ( RGF_USER_FW_REV_ID ) ;
2014-03-17 17:34:10 +04:00
rev_id = wil - > hw_version & 0xff ;
2014-07-14 10:49:37 +04:00
/* Clear MAC link up */
S ( RGF_HP_CTRL , BIT ( 15 ) ) ;
2014-09-10 17:34:30 +04:00
S ( RGF_USER_CLKS_CTL_SW_RST_MASK_0 , BIT_HPAL_PERST_FROM_PAD ) ;
S ( RGF_USER_CLKS_CTL_SW_RST_MASK_0 , BIT_CAR_PERST_RST ) ;
wil_halt_cpu ( wil ) ;
2012-12-21 01:13:19 +04:00
2014-12-01 16:36:31 +03:00
/* Clear Fw Download notification */
C ( RGF_USER_USAGE_6 , BIT ( 0 ) ) ;
2014-07-14 10:49:37 +04:00
if ( is_sparrow ) {
2014-10-28 17:50:07 +03:00
S ( RGF_CAF_OSC_CONTROL , BIT_CAF_OSC_XTAL_EN ) ;
/* XTAL stabilization should take about 3ms */
usleep_range ( 5000 , 7000 ) ;
x = R ( RGF_CAF_PLL_LOCK_STATUS ) ;
if ( ! ( x & BIT_CAF_OSC_DIG_XTAL_STABLE ) ) {
wil_err ( wil , " Xtal stabilization timeout \n "
" RGF_CAF_PLL_LOCK_STATUS = 0x%08x \n " , x ) ;
return - ETIME ;
}
/* switch 10k to XTAL*/
C ( RGF_USER_SPARROW_M_4 , BIT_SPARROW_M_4_SEL_SLEEP_OR_REF ) ;
/* 40 MHz */
C ( RGF_USER_CLKS_CTL_0 , BIT_USER_CLKS_CAR_AHB_SW_SEL ) ;
2014-07-14 10:49:37 +04:00
W ( RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 , 0x3ff81f ) ;
2014-09-10 17:34:30 +04:00
W ( RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 , 0xf ) ;
2014-07-14 10:49:37 +04:00
}
2012-12-21 01:13:19 +04:00
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_2 , 0xFE000000 ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_1 , 0x0000003F ) ;
2014-09-10 17:34:30 +04:00
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_3 , is_sparrow ? 0x000000f0 : 0x00000170 ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_0 , 0xFFE7FE00 ) ;
2012-12-21 01:13:19 +04:00
2014-07-14 10:49:37 +04:00
if ( is_sparrow ) {
W ( RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 , 0x0 ) ;
2014-09-10 17:34:30 +04:00
W ( RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 , 0x0 ) ;
2014-07-14 10:49:37 +04:00
}
2012-12-21 01:13:19 +04:00
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_3 , 0 ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_2 , 0 ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_1 , 0 ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_0 , 0 ) ;
2014-07-14 10:49:37 +04:00
if ( is_sparrow ) {
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_3 , 0x00000003 ) ;
/* reset A2 PCIE AHB */
2014-03-17 17:34:10 +04:00
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_2 , 0x00008000 ) ;
2014-07-14 10:49:37 +04:00
} else {
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_3 , 0x00000001 ) ;
if ( rev_id = = 1 ) {
/* reset A1 BOTH PCIE AHB & PCIE RGF */
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_2 , 0x00000080 ) ;
} else {
W ( RGF_PCIE_LOS_COUNTER_CTL , BIT ( 6 ) | BIT ( 8 ) ) ;
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_2 , 0x00008000 ) ;
}
2014-03-17 17:34:10 +04:00
}
2014-07-14 10:49:37 +04:00
/* TODO: check order here!!! Erez code is different */
2012-12-21 01:13:19 +04:00
W ( RGF_USER_CLKS_CTL_SW_RST_VEC_0 , 0 ) ;
2014-08-06 11:31:53 +04:00
/* wait until device ready. typical time is 200..250 msec */
2014-03-17 17:34:10 +04:00
do {
2014-08-06 11:31:53 +04:00
msleep ( RST_DELAY ) ;
2014-10-28 17:50:07 +03:00
x = R ( RGF_USER_HW_MACHINE_STATE ) ;
2014-08-06 11:31:53 +04:00
if ( delay + + > RST_COUNT ) {
2014-03-17 17:34:23 +04:00
wil_err ( wil , " Reset not completed, hw_state 0x%08x \n " ,
2014-10-28 17:50:07 +03:00
x ) ;
2014-08-06 11:31:52 +04:00
return - ETIME ;
2014-03-17 17:34:10 +04:00
}
2014-10-28 17:50:07 +03:00
} while ( x ! = HW_MACHINE_BOOT_DONE ) ;
2014-03-17 17:34:10 +04:00
2014-07-14 10:49:37 +04:00
/* TODO: Erez check rev_id != 1 */
if ( ! is_sparrow & & ( rev_id ! = 1 ) )
2014-03-17 17:34:14 +04:00
W ( RGF_PCIE_LOS_COUNTER_CTL , BIT ( 8 ) ) ;
2014-03-17 17:34:10 +04:00
2014-03-17 17:34:15 +04:00
C ( RGF_USER_CLKS_CTL_0 , BIT_USER_CLKS_RST_PWGD ) ;
2014-08-06 11:31:53 +04:00
wil_dbg_misc ( wil , " Reset completed in %d ms \n " , delay * RST_DELAY ) ;
2014-08-06 11:31:52 +04:00
return 0 ;
2014-09-10 17:34:30 +04:00
}
2012-12-21 01:13:19 +04:00
2014-09-22 16:31:41 +04:00
/**
* wil_set_itr_trsh : - apply interrupt coalescing params
*/
void wil_set_itr_trsh ( struct wil6210_priv * wil )
{
/* disable, use usec resolution */
W ( RGF_DMA_ITR_CNT_CRL , BIT_DMA_ITR_CNT_CRL_EXT_TICK ) ;
/* disable interrupt moderation for monitor
* to get better timestamp precision
*/
if ( wil - > wdev - > iftype = = NL80211_IFTYPE_MONITOR )
return ;
wil_info ( wil , " set ITR_TRSH = %d usec \n " , wil - > itr_trsh ) ;
W ( RGF_DMA_ITR_CNT_TRSH , wil - > itr_trsh ) ;
W ( RGF_DMA_ITR_CNT_CRL , BIT_DMA_ITR_CNT_CRL_EN |
BIT_DMA_ITR_CNT_CRL_EXT_TICK ) ; /* start it */
}
2014-03-17 17:34:10 +04:00
# undef R
2012-12-21 01:13:19 +04:00
# undef W
# undef S
2014-03-17 17:34:15 +04:00
# undef C
2012-12-21 01:13:19 +04:00
void wil_mbox_ring_le2cpus ( struct wil6210_mbox_ring * r )
{
le32_to_cpus ( & r - > base ) ;
le16_to_cpus ( & r - > entry_size ) ;
le16_to_cpus ( & r - > size ) ;
le32_to_cpus ( & r - > tail ) ;
le32_to_cpus ( & r - > head ) ;
}
static int wil_wait_for_fw_ready ( struct wil6210_priv * wil )
{
ulong to = msecs_to_jiffies ( 1000 ) ;
ulong left = wait_for_completion_timeout ( & wil - > wmi_ready , to ) ;
2014-09-10 17:34:34 +04:00
2012-12-21 01:13:19 +04:00
if ( 0 = = left ) {
wil_err ( wil , " Firmware not ready \n " ) ;
return - ETIME ;
} else {
2014-04-08 12:36:16 +04:00
wil_info ( wil , " FW ready after %d ms. HW version 0x%08x \n " ,
jiffies_to_msecs ( to - left ) , wil - > hw_version ) ;
2012-12-21 01:13:19 +04:00
}
return 0 ;
}
/*
* We reset all the structures , and we reset the UMAC .
* After calling this routine , you ' re expected to reload
* the firmware .
*/
int wil_reset ( struct wil6210_priv * wil )
{
int rc ;
2014-09-10 17:34:36 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2014-03-17 17:34:25 +04:00
WARN_ON ( ! mutex_is_locked ( & wil - > mutex ) ) ;
2014-09-10 17:34:50 +04:00
WARN_ON ( test_bit ( wil_status_napi_en , & wil - > status ) ) ;
2014-03-17 17:34:25 +04:00
cancel_work_sync ( & wil - > disconnect_worker ) ;
2014-12-01 16:33:15 +03:00
wil6210_disconnect ( wil , NULL , WLAN_REASON_DEAUTH_LEAVING , false ) ;
2014-03-17 17:34:25 +04:00
2014-03-17 17:34:18 +04:00
wil - > status = 0 ; /* prevent NAPI from being scheduled */
2014-03-17 17:34:19 +04:00
if ( wil - > scan_request ) {
wil_dbg_misc ( wil , " Abort scan_request 0x%p \n " ,
wil - > scan_request ) ;
2014-05-27 15:45:48 +04:00
del_timer_sync ( & wil - > scan_timer ) ;
2014-03-17 17:34:19 +04:00
cfg80211_scan_done ( wil - > scan_request , true ) ;
wil - > scan_request = NULL ;
}
2014-09-10 17:34:49 +04:00
wil_mask_irq ( wil ) ;
2013-01-28 20:31:05 +04:00
2012-12-21 01:13:19 +04:00
wmi_event_flush ( wil ) ;
flush_workqueue ( wil - > wmi_wq_conn ) ;
2013-01-28 20:31:05 +04:00
flush_workqueue ( wil - > wmi_wq ) ;
2012-12-21 01:13:19 +04:00
2014-08-06 11:31:52 +04:00
rc = wil_target_reset ( wil ) ;
2014-03-17 17:34:17 +04:00
wil_rx_fini ( wil ) ;
2014-08-06 11:31:52 +04:00
if ( rc )
return rc ;
2014-09-10 17:34:30 +04:00
if ( ! no_fw_load ) {
wil_info ( wil , " Use firmware <%s> \n " , WIL_FW_NAME ) ;
wil_halt_cpu ( wil ) ;
/* Loading f/w from the file */
rc = wil_request_firmware ( wil , WIL_FW_NAME ) ;
if ( rc )
return rc ;
/* clear any interrupts which on-card-firmware may have set */
wil6210_clear_irq ( wil ) ;
{ /* CAF_ICR - clear and mask */
u32 a = HOSTADDR ( RGF_CAF_ICR ) +
offsetof ( struct RGF_ICR , ICR ) ;
u32 m = HOSTADDR ( RGF_CAF_ICR ) +
offsetof ( struct RGF_ICR , IMV ) ;
u32 icr = ioread32 ( wil - > csr + a ) ;
iowrite32 ( icr , wil - > csr + a ) ; /* W1C */
iowrite32 ( ~ 0 , wil - > csr + m ) ;
wmb ( ) ; /* wait for completion */
}
wil_release_cpu ( wil ) ;
} else {
wil_info ( wil , " Use firmware from on-card flash \n " ) ;
}
2014-03-17 17:34:17 +04:00
2012-12-21 01:13:19 +04:00
/* init after reset */
wil - > pending_connect_cid = - 1 ;
2013-11-15 02:32:02 +04:00
reinit_completion ( & wil - > wmi_ready ) ;
2014-09-10 17:34:46 +04:00
reinit_completion ( & wil - > wmi_call ) ;
2012-12-21 01:13:19 +04:00
2014-09-10 17:34:49 +04:00
wil_unmask_irq ( wil ) ;
2012-12-21 01:13:19 +04:00
/* we just started MAC, wait for FW ready */
rc = wil_wait_for_fw_ready ( wil ) ;
return rc ;
}
2014-03-17 17:34:19 +04:00
void wil_fw_error_recovery ( struct wil6210_priv * wil )
{
wil_dbg_misc ( wil , " starting fw error recovery \n " ) ;
2014-10-01 16:05:24 +04:00
wil - > recovery_state = fw_recovery_pending ;
2014-03-17 17:34:19 +04:00
schedule_work ( & wil - > fw_error_worker ) ;
}
2012-12-21 01:13:19 +04:00
void wil_link_on ( struct wil6210_priv * wil )
{
struct net_device * ndev = wil_to_ndev ( wil ) ;
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2012-12-21 01:13:19 +04:00
netif_carrier_on ( ndev ) ;
2014-06-16 20:37:23 +04:00
wil_dbg_misc ( wil , " netif_tx_wake : link on \n " ) ;
2012-12-21 01:13:19 +04:00
netif_tx_wake_all_queues ( ndev ) ;
}
void wil_link_off ( struct wil6210_priv * wil )
{
struct net_device * ndev = wil_to_ndev ( wil ) ;
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2012-12-21 01:13:19 +04:00
netif_tx_stop_all_queues ( ndev ) ;
2014-06-16 20:37:23 +04:00
wil_dbg_misc ( wil , " netif_tx_stop : link off \n " ) ;
2012-12-21 01:13:19 +04:00
netif_carrier_off ( ndev ) ;
}
2014-09-10 17:34:50 +04:00
int __wil_up ( struct wil6210_priv * wil )
2012-12-21 01:13:19 +04:00
{
struct net_device * ndev = wil_to_ndev ( wil ) ;
struct wireless_dev * wdev = wil - > wdev ;
int rc ;
2014-03-17 17:34:25 +04:00
WARN_ON ( ! mutex_is_locked ( & wil - > mutex ) ) ;
2012-12-21 01:13:19 +04:00
rc = wil_reset ( wil ) ;
if ( rc )
return rc ;
2013-06-09 10:12:55 +04:00
/* Rx VRING. After MAC and beacon */
2014-12-01 16:35:02 +03:00
rc = wil_rx_init ( wil , 1 < < rx_ring_order ) ;
2013-06-09 10:12:55 +04:00
if ( rc )
return rc ;
2012-12-21 01:13:19 +04:00
switch ( wdev - > iftype ) {
case NL80211_IFTYPE_STATION :
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " type: STATION \n " ) ;
2012-12-21 01:13:19 +04:00
ndev - > type = ARPHRD_ETHER ;
break ;
case NL80211_IFTYPE_AP :
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " type: AP \n " ) ;
2012-12-21 01:13:19 +04:00
ndev - > type = ARPHRD_ETHER ;
break ;
case NL80211_IFTYPE_P2P_CLIENT :
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " type: P2P_CLIENT \n " ) ;
2012-12-21 01:13:19 +04:00
ndev - > type = ARPHRD_ETHER ;
break ;
case NL80211_IFTYPE_P2P_GO :
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " type: P2P_GO \n " ) ;
2012-12-21 01:13:19 +04:00
ndev - > type = ARPHRD_ETHER ;
break ;
case NL80211_IFTYPE_MONITOR :
2013-01-28 20:31:06 +04:00
wil_dbg_misc ( wil , " type: Monitor \n " ) ;
2012-12-21 01:13:19 +04:00
ndev - > type = ARPHRD_IEEE80211_RADIOTAP ;
/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
break ;
default :
return - EOPNOTSUPP ;
}
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address ( wil , ndev - > dev_addr ) ;
2014-09-10 17:34:50 +04:00
wil_dbg_misc ( wil , " NAPI enable \n " ) ;
2013-05-12 15:43:36 +04:00
napi_enable ( & wil - > napi_rx ) ;
napi_enable ( & wil - > napi_tx ) ;
2014-03-17 17:34:18 +04:00
set_bit ( wil_status_napi_en , & wil - > status ) ;
2013-05-12 15:43:36 +04:00
2014-09-10 17:34:35 +04:00
if ( wil - > platform_ops . bus_request )
wil - > platform_ops . bus_request ( wil - > platform_handle ,
WIL_MAX_BUS_REQUEST_KBPS ) ;
2012-12-21 01:13:19 +04:00
return 0 ;
}
int wil_up ( struct wil6210_priv * wil )
{
int rc ;
2014-09-10 17:34:36 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2012-12-21 01:13:19 +04:00
mutex_lock ( & wil - > mutex ) ;
rc = __wil_up ( wil ) ;
mutex_unlock ( & wil - > mutex ) ;
return rc ;
}
2014-09-10 17:34:50 +04:00
int __wil_down ( struct wil6210_priv * wil )
2012-12-21 01:13:19 +04:00
{
2014-09-10 17:34:38 +04:00
int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
WAIT_FOR_DISCONNECT_INTERVAL_MS ;
2014-03-17 17:34:25 +04:00
WARN_ON ( ! mutex_is_locked ( & wil - > mutex ) ) ;
2014-09-10 17:34:35 +04:00
if ( wil - > platform_ops . bus_request )
wil - > platform_ops . bus_request ( wil - > platform_handle , 0 ) ;
2014-09-10 17:34:50 +04:00
wil_disable_irq ( wil ) ;
if ( test_and_clear_bit ( wil_status_napi_en , & wil - > status ) ) {
napi_disable ( & wil - > napi_rx ) ;
napi_disable ( & wil - > napi_tx ) ;
wil_dbg_misc ( wil , " NAPI disable \n " ) ;
}
wil_enable_irq ( wil ) ;
2013-05-12 15:43:36 +04:00
2012-12-21 01:13:19 +04:00
if ( wil - > scan_request ) {
2014-06-16 20:37:11 +04:00
wil_dbg_misc ( wil , " Abort scan_request 0x%p \n " ,
wil - > scan_request ) ;
2014-05-27 15:45:48 +04:00
del_timer_sync ( & wil - > scan_timer ) ;
2012-12-21 01:13:19 +04:00
cfg80211_scan_done ( wil - > scan_request , true ) ;
wil - > scan_request = NULL ;
}
2014-09-10 17:34:38 +04:00
if ( test_bit ( wil_status_fwconnected , & wil - > status ) | |
test_bit ( wil_status_fwconnecting , & wil - > status ) )
wmi_send ( wil , WMI_DISCONNECT_CMDID , NULL , 0 ) ;
/* make sure wil is idle (not connected) */
mutex_unlock ( & wil - > mutex ) ;
while ( iter - - ) {
int idle = ! test_bit ( wil_status_fwconnected , & wil - > status ) & &
! test_bit ( wil_status_fwconnecting , & wil - > status ) ;
if ( idle )
break ;
msleep ( WAIT_FOR_DISCONNECT_INTERVAL_MS ) ;
}
mutex_lock ( & wil - > mutex ) ;
if ( ! iter )
wil_err ( wil , " timeout waiting for idle FW/HW \n " ) ;
2012-12-21 01:13:19 +04:00
wil_rx_fini ( wil ) ;
return 0 ;
}
int wil_down ( struct wil6210_priv * wil )
{
int rc ;
2014-09-10 17:34:36 +04:00
wil_dbg_misc ( wil , " %s() \n " , __func__ ) ;
2014-10-01 16:05:24 +04:00
wil_set_recovery_state ( wil , fw_recovery_idle ) ;
2012-12-21 01:13:19 +04:00
mutex_lock ( & wil - > mutex ) ;
rc = __wil_down ( wil ) ;
mutex_unlock ( & wil - > mutex ) ;
return rc ;
}
2014-02-27 18:20:43 +04:00
int wil_find_cid ( struct wil6210_priv * wil , const u8 * mac )
{
int i ;
int rc = - ENOENT ;
for ( i = 0 ; i < ARRAY_SIZE ( wil - > sta ) ; i + + ) {
if ( ( wil - > sta [ i ] . status ! = wil_sta_unused ) & &
2014-02-27 18:20:53 +04:00
ether_addr_equal ( wil - > sta [ i ] . addr , mac ) ) {
2014-02-27 18:20:43 +04:00
rc = i ;
break ;
}
}
return rc ;
}