Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1f807827
Commit
1f807827
authored
Aug 02, 2013
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge tag 'for-linville-20130730' of
git://github.com/kvalo/ath6kl
parents
20416229
424121c3
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
959 additions
and
454 deletions
+959
-454
drivers/net/wireless/ath/ath10k/bmi.c
drivers/net/wireless/ath/ath10k/bmi.c
+10
-2
drivers/net/wireless/ath/ath10k/bmi.h
drivers/net/wireless/ath/ath10k/bmi.h
+1
-0
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.c
+1
-1
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.c
+210
-111
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/core.h
+36
-14
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.c
+73
-14
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/hif.h
+44
-5
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.c
+25
-36
drivers/net/wireless/ath/ath10k/htc.h
drivers/net/wireless/ath/ath10k/htc.h
+3
-5
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.c
+14
-13
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt.h
+1
-2
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_rx.c
+2
-1
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
+6
-6
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/mac.c
+346
-63
drivers/net/wireless/ath/ath10k/mac.h
drivers/net/wireless/ath/ath10k/mac.h
+1
-0
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.c
+129
-175
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/pci.h
+2
-2
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.c
+36
-4
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath10k/wmi.h
+19
-0
No files found.
drivers/net/wireless/ath/ath10k/bmi.c
View file @
1f807827
...
...
@@ -20,6 +20,12 @@
#include "debug.h"
#include "htc.h"
void
ath10k_bmi_start
(
struct
ath10k
*
ar
)
{
ath10k_dbg
(
ATH10K_DBG_CORE
,
"BMI started
\n
"
);
ar
->
bmi
.
done_sent
=
false
;
}
int
ath10k_bmi_done
(
struct
ath10k
*
ar
)
{
struct
bmi_cmd
cmd
;
...
...
@@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
ret
=
ath10k_hif_exchange_bmi_msg
(
ar
,
&
cmd
,
cmdlen
,
&
resp
,
&
rxlen
);
if
(
ret
)
{
ath10k_warn
(
"unable to read from the device
\n
"
);
ath10k_warn
(
"unable to read from the device (%d)
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
ret
=
ath10k_hif_exchange_bmi_msg
(
ar
,
&
cmd
,
hdrlen
+
txlen
,
NULL
,
NULL
);
if
(
ret
)
{
ath10k_warn
(
"unable to write to the device
\n
"
);
ath10k_warn
(
"unable to write to the device (%d)
\n
"
,
ret
);
return
ret
;
}
...
...
drivers/net/wireless/ath/ath10k/bmi.h
View file @
1f807827
...
...
@@ -184,6 +184,7 @@ struct bmi_target_info {
#define BMI_CE_NUM_TO_TARG 0
#define BMI_CE_NUM_TO_HOST 1
void
ath10k_bmi_start
(
struct
ath10k
*
ar
);
int
ath10k_bmi_done
(
struct
ath10k
*
ar
);
int
ath10k_bmi_get_target_info
(
struct
ath10k
*
ar
,
struct
bmi_target_info
*
target_info
);
...
...
drivers/net/wireless/ath/ath10k/ce.c
View file @
1f807827
...
...
@@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar,
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
void
__iomem
*
indicator_addr
;
if
(
!
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
,
ar_pci
->
features
))
{
if
(
!
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
,
ar_pci
->
features
))
{
ath10k_pci_write32
(
ar
,
ce_ctrl_addr
+
SR_WR_INDEX_ADDRESS
,
n
);
return
;
}
...
...
drivers/net/wireless/ath/ath10k/core.c
View file @
1f807827
...
...
@@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
goto
conn_fail
;
/* Start HTC */
status
=
ath10k_htc_start
(
ar
->
htc
);
status
=
ath10k_htc_start
(
&
ar
->
htc
);
if
(
status
)
goto
conn_fail
;
...
...
@@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
return
0
;
timeout:
ath10k_htc_stop
(
ar
->
htc
);
ath10k_htc_stop
(
&
ar
->
htc
);
conn_fail:
return
status
;
}
...
...
@@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
static
int
ath10k_download_board_data
(
struct
ath10k
*
ar
)
{
const
struct
firmware
*
fw
=
ar
->
board_data
;
u32
board_data_size
=
QCA988X_BOARD_DATA_SZ
;
u32
address
;
const
struct
firmware
*
fw
;
int
ret
;
fw
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
board
);
if
(
IS_ERR
(
fw
))
{
ath10k_err
(
"could not fetch board data fw file (%ld)
\n
"
,
PTR_ERR
(
fw
));
return
PTR_ERR
(
fw
);
}
ret
=
ath10k_push_board_ext_data
(
ar
,
fw
);
if
(
ret
)
{
ath10k_err
(
"could not push board ext data (%d)
\n
"
,
ret
);
...
...
@@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar)
}
exit:
release_firmware
(
fw
);
return
ret
;
}
static
int
ath10k_download_and_run_otp
(
struct
ath10k
*
ar
)
{
const
struct
firmware
*
fw
;
u32
address
;
const
struct
firmware
*
fw
=
ar
->
otp
;
u32
address
=
ar
->
hw_params
.
patch_load_addr
;
u32
exec_param
;
int
ret
;
/* OTP is optional */
if
(
ar
->
hw_params
.
fw
.
otp
==
NULL
)
{
ath10k_info
(
"otp file not defined
\n
"
);
return
0
;
}
address
=
ar
->
hw_params
.
patch_load_addr
;
fw
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
otp
);
if
(
IS_ERR
(
fw
))
{
ath10k_warn
(
"could not fetch otp (%ld)
\n
"
,
PTR_ERR
(
fw
));
if
(
!
ar
->
otp
)
return
0
;
}
ret
=
ath10k_bmi_fast_download
(
ar
,
address
,
fw
->
data
,
fw
->
size
);
if
(
ret
)
{
...
...
@@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
}
exit:
release_firmware
(
fw
);
return
ret
;
}
static
int
ath10k_download_fw
(
struct
ath10k
*
ar
)
{
const
struct
firmware
*
fw
;
const
struct
firmware
*
fw
=
ar
->
firmware
;
u32
address
;
int
ret
;
if
(
ar
->
hw_params
.
fw
.
fw
==
NULL
)
return
-
EINVAL
;
address
=
ar
->
hw_params
.
patch_load_addr
;
fw
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
fw
);
if
(
IS_ERR
(
fw
))
{
ath10k_err
(
"could not fetch fw (%ld)
\n
"
,
PTR_ERR
(
fw
));
return
PTR_ERR
(
fw
);
}
ret
=
ath10k_bmi_fast_download
(
ar
,
address
,
fw
->
data
,
fw
->
size
);
if
(
ret
)
{
ath10k_err
(
"could not write fw (%d)
\n
"
,
ret
);
...
...
@@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar)
}
exit:
release_firmware
(
fw
);
return
ret
;
}
static
void
ath10k_core_free_firmware_files
(
struct
ath10k
*
ar
)
{
if
(
ar
->
board_data
&&
!
IS_ERR
(
ar
->
board_data
))
release_firmware
(
ar
->
board_data
);
if
(
ar
->
otp
&&
!
IS_ERR
(
ar
->
otp
))
release_firmware
(
ar
->
otp
);
if
(
ar
->
firmware
&&
!
IS_ERR
(
ar
->
firmware
))
release_firmware
(
ar
->
firmware
);
ar
->
board_data
=
NULL
;
ar
->
otp
=
NULL
;
ar
->
firmware
=
NULL
;
}
static
int
ath10k_core_fetch_firmware_files
(
struct
ath10k
*
ar
)
{
int
ret
=
0
;
if
(
ar
->
hw_params
.
fw
.
fw
==
NULL
)
{
ath10k_err
(
"firmware file not defined
\n
"
);
return
-
EINVAL
;
}
if
(
ar
->
hw_params
.
fw
.
board
==
NULL
)
{
ath10k_err
(
"board data file not defined"
);
return
-
EINVAL
;
}
ar
->
board_data
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
board
);
if
(
IS_ERR
(
ar
->
board_data
))
{
ret
=
PTR_ERR
(
ar
->
board_data
);
ath10k_err
(
"could not fetch board data (%d)
\n
"
,
ret
);
goto
err
;
}
ar
->
firmware
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
fw
);
if
(
IS_ERR
(
ar
->
firmware
))
{
ret
=
PTR_ERR
(
ar
->
firmware
);
ath10k_err
(
"could not fetch firmware (%d)
\n
"
,
ret
);
goto
err
;
}
/* OTP may be undefined. If so, don't fetch it at all */
if
(
ar
->
hw_params
.
fw
.
otp
==
NULL
)
return
0
;
ar
->
otp
=
ath10k_fetch_fw_file
(
ar
,
ar
->
hw_params
.
fw
.
dir
,
ar
->
hw_params
.
fw
.
otp
);
if
(
IS_ERR
(
ar
->
otp
))
{
ret
=
PTR_ERR
(
ar
->
otp
);
ath10k_err
(
"could not fetch otp (%d)
\n
"
,
ret
);
goto
err
;
}
return
0
;
err:
ath10k_core_free_firmware_files
(
ar
);
return
ret
;
}
...
...
@@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar)
return
0
;
}
static
void
ath10k_core_restart
(
struct
work_struct
*
work
)
{
struct
ath10k
*
ar
=
container_of
(
work
,
struct
ath10k
,
restart_work
);
mutex_lock
(
&
ar
->
conf_mutex
);
switch
(
ar
->
state
)
{
case
ATH10K_STATE_ON
:
ath10k_halt
(
ar
);
ar
->
state
=
ATH10K_STATE_RESTARTING
;
ieee80211_restart_hw
(
ar
->
hw
);
break
;
case
ATH10K_STATE_OFF
:
/* this can happen if driver is being unloaded */
ath10k_warn
(
"cannot restart a device that hasn't been started
\n
"
);
break
;
case
ATH10K_STATE_RESTARTING
:
case
ATH10K_STATE_RESTARTED
:
ar
->
state
=
ATH10K_STATE_WEDGED
;
/* fall through */
case
ATH10K_STATE_WEDGED
:
ath10k_warn
(
"device is wedged, will not restart
\n
"
);
break
;
}
mutex_unlock
(
&
ar
->
conf_mutex
);
}
struct
ath10k
*
ath10k_core_create
(
void
*
hif_priv
,
struct
device
*
dev
,
enum
ath10k_bus
bus
,
const
struct
ath10k_hif_ops
*
hif_ops
)
{
struct
ath10k
*
ar
;
...
...
@@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
ar
->
hif
.
priv
=
hif_priv
;
ar
->
hif
.
ops
=
hif_ops
;
ar
->
hif
.
bus
=
bus
;
ar
->
free_vdev_map
=
0xFF
;
/* 8 vdevs */
init_completion
(
&
ar
->
scan
.
started
);
init_completion
(
&
ar
->
scan
.
completed
);
...
...
@@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_waitqueue_head
(
&
ar
->
event_queue
);
INIT_WORK
(
&
ar
->
restart_work
,
ath10k_core_restart
);
return
ar
;
err_wq:
...
...
@@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar)
}
EXPORT_SYMBOL
(
ath10k_core_destroy
);
int
ath10k_core_register
(
struct
ath10k
*
ar
)
int
ath10k_core_start
(
struct
ath10k
*
ar
)
{
struct
ath10k_htc_ops
htc_ops
;
struct
bmi_target_info
target_info
;
int
status
;
memset
(
&
target_info
,
0
,
sizeof
(
target_info
));
status
=
ath10k_bmi_get_target_info
(
ar
,
&
target_info
);
if
(
status
)
goto
err
;
ar
->
target_version
=
target_info
.
version
;
ar
->
hw
->
wiphy
->
hw_version
=
target_info
.
version
;
status
=
ath10k_init_hw_params
(
ar
);
if
(
status
)
goto
err
;
ath10k_bmi_start
(
ar
);
if
(
ath10k_init_configure_target
(
ar
))
{
status
=
-
EINVAL
;
...
...
@@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar)
if
(
status
)
goto
err
;
htc_ops
.
target_send_suspend_complete
=
ath10k_send_suspend_complete
;
ar
->
htc
.
htc_ops
.
target_send_suspend_complete
=
ath10k_send_suspend_complete
;
ar
->
htc
=
ath10k_htc_create
(
ar
,
&
htc_ops
);
if
(
IS_ERR
(
ar
->
htc
))
{
status
=
PTR_ERR
(
ar
->
htc
);
ath10k_err
(
"could not create HTC (%d)
\n
"
,
status
);
status
=
ath10k_htc_init
(
ar
);
if
(
status
)
{
ath10k_err
(
"could not init HTC (%d)
\n
"
,
status
);
goto
err
;
}
status
=
ath10k_bmi_done
(
ar
);
if
(
status
)
goto
err
_htc_destroy
;
goto
err
;
status
=
ath10k_wmi_attach
(
ar
);
if
(
status
)
{
ath10k_err
(
"WMI attach failed: %d
\n
"
,
status
);
goto
err
_htc_destroy
;
goto
err
;
}
status
=
ath10k_htc_wait_target
(
ar
->
htc
);
status
=
ath10k_htc_wait_target
(
&
ar
->
htc
);
if
(
status
)
goto
err_wmi_detach
;
ar
->
htt
=
ath10k_htt_attach
(
ar
);
if
(
!
ar
->
htt
)
{
status
=
-
ENOMEM
;
status
=
ath10k_htt_attach
(
ar
);
if
(
status
)
{
ath10k_err
(
"could not attach htt (%d)
\n
"
,
status
)
;
goto
err_wmi_detach
;
}
...
...
@@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar)
goto
err_disconnect_htc
;
}
status
=
ath10k_htt_attach_target
(
ar
->
htt
);
if
(
status
)
goto
err_disconnect_htc
;
status
=
ath10k_mac_register
(
ar
);
status
=
ath10k_htt_attach_target
(
&
ar
->
htt
);
if
(
status
)
goto
err_disconnect_htc
;
status
=
ath10k_debug_create
(
ar
);
if
(
status
)
{
ath10k_err
(
"unable to initialize debugfs
\n
"
);
goto
err_unregister_mac
;
}
ar
->
free_vdev_map
=
(
1
<<
TARGET_NUM_VDEVS
)
-
1
;
return
0
;
err_unregister_mac:
ath10k_mac_unregister
(
ar
);
err_disconnect_htc:
ath10k_htc_stop
(
ar
->
htc
);
ath10k_htc_stop
(
&
ar
->
htc
);
err_htt_detach:
ath10k_htt_detach
(
ar
->
htt
);
ath10k_htt_detach
(
&
ar
->
htt
);
err_wmi_detach:
ath10k_wmi_detach
(
ar
);
err_htc_destroy:
ath10k_htc_destroy
(
ar
->
htc
);
err:
return
status
;
}
EXPORT_SYMBOL
(
ath10k_core_
register
);
EXPORT_SYMBOL
(
ath10k_core_
start
);
void
ath10k_core_
unregister
(
struct
ath10k
*
ar
)
void
ath10k_core_
stop
(
struct
ath10k
*
ar
)
{
/* We must unregister from mac80211 before we stop HTC and HIF.
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister
(
ar
);
ath10k_htc_stop
(
ar
->
htc
);
ath10k_htt_detach
(
ar
->
htt
);
ath10k_htc_stop
(
&
ar
->
htc
);
ath10k_htt_detach
(
&
ar
->
htt
);
ath10k_wmi_detach
(
ar
);
ath10k_htc_destroy
(
ar
->
htc
);
}
EXPORT_SYMBOL
(
ath10k_core_
unregister
);
EXPORT_SYMBOL
(
ath10k_core_
stop
);
int
ath10k_core_target_suspend
(
struct
ath10k
*
ar
)
/* mac80211 manages fw/hw initialization through start/stop hooks. However in
* order to know what hw capabilities should be advertised to mac80211 it is
* necessary to load the firmware (and tear it down immediately since start
* hook will try to init it again) before registering */
static
int
ath10k_core_probe_fw
(
struct
ath10k
*
ar
)
{
int
ret
;
struct
bmi_target_info
target_info
;
int
ret
=
0
;
ath10k_dbg
(
ATH10K_DBG_CORE
,
"%s: called"
,
__func__
);
ret
=
ath10k_hif_power_up
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not start pci hif (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
ath10k_wmi_pdev_suspend_target
(
ar
);
if
(
ret
)
ath10k_warn
(
"could not suspend target (%d)
\n
"
,
ret
);
memset
(
&
target_info
,
0
,
sizeof
(
target_info
));
ret
=
ath10k_bmi_get_target_info
(
ar
,
&
target_info
);
if
(
ret
)
{
ath10k_err
(
"could not get target info (%d)
\n
"
,
ret
);
ath10k_hif_power_down
(
ar
);
return
ret
;
}
ar
->
target_version
=
target_info
.
version
;
ar
->
hw
->
wiphy
->
hw_version
=
target_info
.
version
;
ret
=
ath10k_init_hw_params
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not get hw params (%d)
\n
"
,
ret
);
ath10k_hif_power_down
(
ar
);
return
ret
;
}
ret
=
ath10k_core_fetch_firmware_files
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not fetch firmware files (%d)
\n
"
,
ret
);
ath10k_hif_power_down
(
ar
);
return
ret
;
}
ret
=
ath10k_core_start
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not init core (%d)
\n
"
,
ret
);
ath10k_core_free_firmware_files
(
ar
);
ath10k_hif_power_down
(
ar
);
return
ret
;
}
ath10k_core_stop
(
ar
);
ath10k_hif_power_down
(
ar
);
return
0
;
}
EXPORT_SYMBOL
(
ath10k_core_target_suspend
);
int
ath10k_core_
target_resume
(
struct
ath10k
*
ar
)
int
ath10k_core_
register
(
struct
ath10k
*
ar
)
{
int
ret
;
int
status
;
ath10k_dbg
(
ATH10K_DBG_CORE
,
"%s: called"
,
__func__
);
status
=
ath10k_core_probe_fw
(
ar
);
if
(
status
)
{
ath10k_err
(
"could not probe fw (%d)
\n
"
,
status
);
return
status
;
}
ret
=
ath10k_wmi_pdev_resume_target
(
ar
);
if
(
ret
)
ath10k_warn
(
"could not resume target (%d)
\n
"
,
ret
);
status
=
ath10k_mac_register
(
ar
);
if
(
status
)
{
ath10k_err
(
"could not register to mac80211 (%d)
\n
"
,
status
);
goto
err_release_fw
;
}
return
ret
;
status
=
ath10k_debug_create
(
ar
);
if
(
status
)
{
ath10k_err
(
"unable to initialize debugfs
\n
"
);
goto
err_unregister_mac
;
}
return
0
;
err_unregister_mac:
ath10k_mac_unregister
(
ar
);
err_release_fw:
ath10k_core_free_firmware_files
(
ar
);
return
status
;
}
EXPORT_SYMBOL
(
ath10k_core_target_resume
);
EXPORT_SYMBOL
(
ath10k_core_register
);
void
ath10k_core_unregister
(
struct
ath10k
*
ar
)
{
/* We must unregister from mac80211 before we stop HTC and HIF.
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister
(
ar
);
ath10k_core_free_firmware_files
(
ar
);
}
EXPORT_SYMBOL
(
ath10k_core_unregister
);
MODULE_AUTHOR
(
"Qualcomm Atheros"
);
MODULE_DESCRIPTION
(
"Core module for QCA988X PCIe devices."
);
...
...
drivers/net/wireless/ath/ath10k/core.h
View file @
1f807827
...
...
@@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include "htt.h"
#include "htc.h"
#include "hw.h"
#include "targaddrs.h"
...
...
@@ -43,10 +44,6 @@
struct
ath10k
;
enum
ath10k_bus
{
ATH10K_BUS_PCI
,
};
struct
ath10k_skb_cb
{
dma_addr_t
paddr
;
bool
is_mapped
;
...
...
@@ -250,6 +247,28 @@ struct ath10k_debug {
struct
completion
event_stats_compl
;
};
enum
ath10k_state
{
ATH10K_STATE_OFF
=
0
,
ATH10K_STATE_ON
,
/* When doing firmware recovery the device is first powered down.
* mac80211 is supposed to call in to start() hook later on. It is
* however possible that driver unloading and firmware crash overlap.
* mac80211 can wait on conf_mutex in stop() while the device is
* stopped in ath10k_core_restart() work holding conf_mutex. The state
* RESTARTED means that the device is up and mac80211 has started hw
* reconfiguration. Once mac80211 is done with the reconfiguration we
* set the state to STATE_ON in restart_complete(). */
ATH10K_STATE_RESTARTING
,
ATH10K_STATE_RESTARTED
,
/* The device has crashed while restarting hw. This state is like ON
* but commands are blocked in HTC and -ECOMM response is given. This
* prevents completion timeouts and makes the driver more responsive to
* userspace commands. This is also prevents recursive recovery. */
ATH10K_STATE_WEDGED
,
};
struct
ath10k
{
struct
ath_common
ath_common
;
struct
ieee80211_hw
*
hw
;
...
...
@@ -274,19 +293,16 @@ struct ath10k {
struct
{
void
*
priv
;
enum
ath10k_bus
bus
;
const
struct
ath10k_hif_ops
*
ops
;
}
hif
;
struct
ath10k_wmi
wmi
;
wait_queue_head_t
event_queue
;
bool
is_target_paused
;
struct
ath10k_bmi
bmi
;
struct
ath10k_htc
*
htc
;
struct
ath10k_htt
*
htt
;
struct
ath10k_wmi
wmi
;
struct
ath10k_htc
htc
;
struct
ath10k_htt
htt
;
struct
ath10k_hw_params
{
u32
id
;
...
...
@@ -301,6 +317,10 @@ struct ath10k {
}
fw
;
}
hw_params
;
const
struct
firmware
*
board_data
;
const
struct
firmware
*
otp
;
const
struct
firmware
*
firmware
;
struct
{
struct
completion
started
;
struct
completion
completed
;
...
...
@@ -350,20 +370,22 @@ struct ath10k {
struct
completion
offchan_tx_completed
;
struct
sk_buff
*
offchan_tx_skb
;
enum
ath10k_state
state
;
struct
work_struct
restart_work
;
#ifdef CONFIG_ATH10K_DEBUGFS
struct
ath10k_debug
debug
;
#endif
};
struct
ath10k
*
ath10k_core_create
(
void
*
hif_priv
,
struct
device
*
dev
,
enum
ath10k_bus
bus
,
const
struct
ath10k_hif_ops
*
hif_ops
);
void
ath10k_core_destroy
(
struct
ath10k
*
ar
);
int
ath10k_core_start
(
struct
ath10k
*
ar
);
void
ath10k_core_stop
(
struct
ath10k
*
ar
);
int
ath10k_core_register
(
struct
ath10k
*
ar
);
void
ath10k_core_unregister
(
struct
ath10k
*
ar
);
int
ath10k_core_target_suspend
(
struct
ath10k
*
ar
);
int
ath10k_core_target_resume
(
struct
ath10k
*
ar
);
#endif
/* _CORE_H_ */
drivers/net/wireless/ath/ath10k/debug.c
View file @
1f807827
...
...
@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
struct
wmi_pdev_stats
*
ps
;
int
i
;
mutex_lock
(
&
ar
->
conf_mutex
);
spin_lock_bh
(
&
ar
->
data_lock
);
stats
=
&
ar
->
debug
.
target_stats
;
...
...
@@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
}
}
spin_unlock_bh
(
&
ar
->
data_lock
);
mutex_unlock
(
&
ar
->
conf_mutex
);
complete
(
&
ar
->
debug
.
event_stats_compl
);
}
...
...
@@ -268,35 +269,35 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
{
struct
ath10k
*
ar
=
file
->
private_data
;
struct
ath10k_target_stats
*
fw_stats
;
char
*
buf
;
char
*
buf
=
NULL
;
unsigned
int
len
=
0
,
buf_len
=
2500
;
ssize_t
ret_cnt
;
ssize_t
ret_cnt
=
0
;
long
left
;
int
i
;
int
ret
;
fw_stats
=
&
ar
->
debug
.
target_stats
;
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
!=
ATH10K_STATE_ON
)
goto
exit
;
buf
=
kzalloc
(
buf_len
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
goto
exit
;
ret
=
ath10k_wmi_request_stats
(
ar
,
WMI_REQUEST_PEER_STAT
);
if
(
ret
)
{
ath10k_warn
(
"could not request stats (%d)
\n
"
,
ret
);
kfree
(
buf
);
return
-
EIO
;
goto
exit
;
}
left
=
wait_for_completion_timeout
(
&
ar
->
debug
.
event_stats_compl
,
1
*
HZ
);
if
(
left
<=
0
)
goto
exit
;
if
(
left
<=
0
)
{
kfree
(
buf
);
return
-
ETIMEDOUT
;
}
mutex_lock
(
&
ar
->
conf_mutex
);
spin_lock_bh
(
&
ar
->
data_lock
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"
\n
"
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"%30s
\n
"
,
"ath10k PDEV stats"
);
...
...
@@ -424,14 +425,15 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
fw_stats
->
peer_stat
[
i
].
peer_tx_rate
);
len
+=
scnprintf
(
buf
+
len
,
buf_len
-
len
,
"
\n
"
);
}
spin_unlock_bh
(
&
ar
->
data_lock
);
if
(
len
>
buf_len
)
len
=
buf_len
;
ret_cnt
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
exit:
mutex_unlock
(
&
ar
->
conf_mutex
);
kfree
(
buf
);
return
ret_cnt
;
}
...
...
@@ -443,6 +445,60 @@ static const struct file_operations fops_fw_stats = {
.
llseek
=
default_llseek
,
};
static
ssize_t
ath10k_read_simulate_fw_crash
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
const
char
buf
[]
=
"To simulate firmware crash write the keyword"
" `crash` to this file.
\n
This will force firmware"
" to report a crash to the host system.
\n
"
;
return
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
strlen
(
buf
));
}
static
ssize_t
ath10k_write_simulate_fw_crash
(
struct
file
*
file
,
const
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
ath10k
*
ar
=
file
->
private_data
;
char
buf
[
32
]
=
{};
int
ret
;
mutex_lock
(
&
ar
->
conf_mutex
);
simple_write_to_buffer
(
buf
,
sizeof
(
buf
)
-
1
,
ppos
,
user_buf
,
count
);
if
(
strcmp
(
buf
,
"crash"
)
&&
strcmp
(
buf
,
"crash
\n
"
))
{
ret
=
-
EINVAL
;
goto
exit
;
}
if
(
ar
->
state
!=
ATH10K_STATE_ON
&&
ar
->
state
!=
ATH10K_STATE_RESTARTED
)
{
ret
=
-
ENETDOWN
;
goto
exit
;
}
ath10k_info
(
"simulating firmware crash
\n
"
);
ret
=
ath10k_wmi_force_fw_hang
(
ar
,
WMI_FORCE_FW_HANG_ASSERT
,
0
);
if
(
ret
)
ath10k_warn
(
"failed to force fw hang (%d)
\n
"
,
ret
);
if
(
ret
==
0
)
ret
=
count
;
exit:
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
static
const
struct
file_operations
fops_simulate_fw_crash
=
{
.
read
=
ath10k_read_simulate_fw_crash
,
.
write
=
ath10k_write_simulate_fw_crash
,
.
open
=
simple_open
,
.
owner
=
THIS_MODULE
,
.
llseek
=
default_llseek
,
};
int
ath10k_debug_create
(
struct
ath10k
*
ar
)
{
ar
->
debug
.
debugfs_phy
=
debugfs_create_dir
(
"ath10k"
,
...
...
@@ -459,6 +515,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file
(
"wmi_services"
,
S_IRUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_wmi_services
);
debugfs_create_file
(
"simulate_fw_crash"
,
S_IRUSR
,
ar
->
debug
.
debugfs_phy
,
ar
,
&
fops_simulate_fw_crash
);
return
0
;
}
#endif
/* CONFIG_ATH10K_DEBUGFS */
...
...
drivers/net/wireless/ath/ath10k/hif.h
View file @
1f807827
...
...
@@ -46,8 +46,11 @@ struct ath10k_hif_ops {
void
*
request
,
u32
request_len
,
void
*
response
,
u32
*
response_len
);
/* Post BMI phase, after FW is loaded. Starts regular operation */
int
(
*
start
)(
struct
ath10k
*
ar
);
/* Clean up what start() did. This does not revert to BMI phase. If
* desired so, call power_down() and power_up() */
void
(
*
stop
)(
struct
ath10k
*
ar
);
int
(
*
map_service_to_pipe
)(
struct
ath10k
*
ar
,
u16
service_id
,
...
...
@@ -66,10 +69,20 @@ struct ath10k_hif_ops {
*/
void
(
*
send_complete_check
)(
struct
ath10k
*
ar
,
u8
pipe_id
,
int
force
);
void
(
*
init
)(
struct
ath10k
*
ar
,
void
(
*
set_callbacks
)(
struct
ath10k
*
ar
,
struct
ath10k_hif_cb
*
callbacks
);
u16
(
*
get_free_queue_number
)(
struct
ath10k
*
ar
,
u8
pipe_id
);
/* Power up the device and enter BMI transfer mode for FW download */
int
(
*
power_up
)(
struct
ath10k
*
ar
);
/* Power down the device and free up resources. stop() must be called
* before this if start() was called earlier */
void
(
*
power_down
)(
struct
ath10k
*
ar
);
int
(
*
suspend
)(
struct
ath10k
*
ar
);
int
(
*
resume
)(
struct
ath10k
*
ar
);
};
...
...
@@ -122,10 +135,10 @@ static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
ar
->
hif
.
ops
->
send_complete_check
(
ar
,
pipe_id
,
force
);
}
static
inline
void
ath10k_hif_
init
(
struct
ath10k
*
ar
,
static
inline
void
ath10k_hif_
set_callbacks
(
struct
ath10k
*
ar
,
struct
ath10k_hif_cb
*
callbacks
)
{
ar
->
hif
.
ops
->
init
(
ar
,
callbacks
);
ar
->
hif
.
ops
->
set_callbacks
(
ar
,
callbacks
);
}
static
inline
u16
ath10k_hif_get_free_queue_number
(
struct
ath10k
*
ar
,
...
...
@@ -134,4 +147,30 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
return
ar
->
hif
.
ops
->
get_free_queue_number
(
ar
,
pipe_id
);
}
static
inline
int
ath10k_hif_power_up
(
struct
ath10k
*
ar
)
{
return
ar
->
hif
.
ops
->
power_up
(
ar
);
}
static
inline
void
ath10k_hif_power_down
(
struct
ath10k
*
ar
)
{
ar
->
hif
.
ops
->
power_down
(
ar
);
}
static
inline
int
ath10k_hif_suspend
(
struct
ath10k
*
ar
)
{
if
(
!
ar
->
hif
.
ops
->
suspend
)
return
-
EOPNOTSUPP
;
return
ar
->
hif
.
ops
->
suspend
(
ar
);
}
static
inline
int
ath10k_hif_resume
(
struct
ath10k
*
ar
)
{
if
(
!
ar
->
hif
.
ops
->
resume
)
return
-
EOPNOTSUPP
;
return
ar
->
hif
.
ops
->
resume
(
ar
);
}
#endif
/* _HIF_H_ */
drivers/net/wireless/ath/ath10k/htc.c
View file @
1f807827
...
...
@@ -246,15 +246,22 @@ int ath10k_htc_send(struct ath10k_htc *htc,
{
struct
ath10k_htc_ep
*
ep
=
&
htc
->
endpoint
[
eid
];
if
(
htc
->
ar
->
state
==
ATH10K_STATE_WEDGED
)
return
-
ECOMM
;
if
(
eid
>=
ATH10K_HTC_EP_COUNT
)
{
ath10k_warn
(
"Invalid endpoint id: %d
\n
"
,
eid
);
return
-
ENOENT
;
}
skb_push
(
skb
,
sizeof
(
struct
ath10k_htc_hdr
));
spin_lock_bh
(
&
htc
->
tx_lock
);
if
(
htc
->
stopped
)
{
spin_unlock_bh
(
&
htc
->
tx_lock
);
return
-
ESHUTDOWN
;
}
__skb_queue_tail
(
&
ep
->
tx_queue
,
skb
);
skb_push
(
skb
,
sizeof
(
struct
ath10k_htc_hdr
));
spin_unlock_bh
(
&
htc
->
tx_lock
);
queue_work
(
htc
->
ar
->
workqueue
,
&
ep
->
send_work
);
...
...
@@ -265,25 +272,19 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
struct
sk_buff
*
skb
,
unsigned
int
eid
)
{
struct
ath10k_htc
*
htc
=
ar
->
htc
;
struct
ath10k_htc
*
htc
=
&
ar
->
htc
;
struct
ath10k_htc_ep
*
ep
=
&
htc
->
endpoint
[
eid
];
bool
stopping
;
ath10k_htc_notify_tx_completion
(
ep
,
skb
);
/* the skb now belongs to the completion handler */
/* note: when using TX credit flow, the re-checking of queues happens
* when credits flow back from the target. in the non-TX credit case,
* we recheck after the packet completes */
spin_lock_bh
(
&
htc
->
tx_lock
);
stopping
=
htc
->
stopping
;
spin_unlock_bh
(
&
htc
->
tx_lock
);
if
(
!
ep
->
tx_credit_flow_enabled
&&
!
stopping
)
/*
* note: when using TX credit flow, the re-checking of
* queues happens when credits flow back from the target.
* in the non-TX credit case, we recheck after the packet
* completes
*/
if
(
!
ep
->
tx_credit_flow_enabled
&&
!
htc
->
stopped
)
queue_work
(
ar
->
workqueue
,
&
ep
->
send_work
);
spin_unlock_bh
(
&
htc
->
tx_lock
);
return
0
;
}
...
...
@@ -414,7 +415,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
u8
pipe_id
)
{
int
status
=
0
;
struct
ath10k_htc
*
htc
=
ar
->
htc
;
struct
ath10k_htc
*
htc
=
&
ar
->
htc
;
struct
ath10k_htc_hdr
*
hdr
;
struct
ath10k_htc_ep
*
ep
;
u16
payload_len
;
...
...
@@ -751,7 +752,8 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
tx_alloc
=
ath10k_htc_get_credit_allocation
(
htc
,
conn_req
->
service_id
);
if
(
!
tx_alloc
)
ath10k_warn
(
"HTC Service %s does not allocate target credits
\n
"
,
ath10k_dbg
(
ATH10K_DBG_HTC
,
"HTC Service %s does not allocate target credits
\n
"
,
htc_service_name
(
conn_req
->
service_id
));
skb
=
ath10k_htc_build_tx_ctrl_skb
(
htc
->
ar
);
...
...
@@ -947,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
struct
ath10k_htc_ep
*
ep
;
spin_lock_bh
(
&
htc
->
tx_lock
);
htc
->
stopp
ing
=
true
;
htc
->
stopp
ed
=
true
;
spin_unlock_bh
(
&
htc
->
tx_lock
);
for
(
i
=
ATH10K_HTC_EP_0
;
i
<
ATH10K_HTC_EP_COUNT
;
i
++
)
{
...
...
@@ -956,26 +958,18 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
}
ath10k_hif_stop
(
htc
->
ar
);
ath10k_htc_reset_endpoint_states
(
htc
);
}
/* registered target arrival callback from the HIF layer */
struct
ath10k_htc
*
ath10k_htc_create
(
struct
ath10k
*
ar
,
struct
ath10k_htc_ops
*
htc_ops
)
int
ath10k_htc_init
(
struct
ath10k
*
ar
)
{
struct
ath10k_hif_cb
htc_callbacks
;
struct
ath10k_htc_ep
*
ep
=
NULL
;
struct
ath10k_htc
*
htc
=
NULL
;
/* FIXME: use struct ath10k instead */
htc
=
kzalloc
(
sizeof
(
struct
ath10k_htc
),
GFP_KERNEL
);
if
(
!
htc
)
return
ERR_PTR
(
-
ENOMEM
);
struct
ath10k_htc
*
htc
=
&
ar
->
htc
;
spin_lock_init
(
&
htc
->
tx_lock
);
memcpy
(
&
htc
->
htc_ops
,
htc_ops
,
sizeof
(
struct
ath10k_htc_ops
));
htc
->
stopped
=
false
;
ath10k_htc_reset_endpoint_states
(
htc
);
/* setup HIF layer callbacks */
...
...
@@ -986,15 +980,10 @@ struct ath10k_htc *ath10k_htc_create(struct ath10k *ar,
/* Get HIF default pipe for HTC message exchange */
ep
=
&
htc
->
endpoint
[
ATH10K_HTC_EP_0
];
ath10k_hif_
init
(
ar
,
&
htc_callbacks
);
ath10k_hif_
set_callbacks
(
ar
,
&
htc_callbacks
);
ath10k_hif_get_default_pipe
(
ar
,
&
ep
->
ul_pipe_id
,
&
ep
->
dl_pipe_id
);
init_completion
(
&
htc
->
ctl_resp
);
return
htc
;
}
void
ath10k_htc_destroy
(
struct
ath10k_htc
*
htc
)
{
kfree
(
htc
);
return
0
;
}
drivers/net/wireless/ath/ath10k/htc.h
View file @
1f807827
...
...
@@ -335,7 +335,7 @@ struct ath10k_htc {
struct
ath10k
*
ar
;
struct
ath10k_htc_ep
endpoint
[
ATH10K_HTC_EP_COUNT
];
/* protects endpoint and stopp
ing
fields */
/* protects endpoint and stopp
ed
fields */
spinlock_t
tx_lock
;
struct
ath10k_htc_ops
htc_ops
;
...
...
@@ -349,11 +349,10 @@ struct ath10k_htc {
struct
ath10k_htc_svc_tx_credits
service_tx_alloc
[
ATH10K_HTC_EP_COUNT
];
int
target_credit_size
;
bool
stopp
ing
;
bool
stopp
ed
;
};
struct
ath10k_htc
*
ath10k_htc_create
(
struct
ath10k
*
ar
,
struct
ath10k_htc_ops
*
htc_ops
);
int
ath10k_htc_init
(
struct
ath10k
*
ar
);
int
ath10k_htc_wait_target
(
struct
ath10k_htc
*
htc
);
int
ath10k_htc_start
(
struct
ath10k_htc
*
htc
);
int
ath10k_htc_connect_service
(
struct
ath10k_htc
*
htc
,
...
...
@@ -362,7 +361,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
int
ath10k_htc_send
(
struct
ath10k_htc
*
htc
,
enum
ath10k_htc_ep_id
eid
,
struct
sk_buff
*
packet
);
void
ath10k_htc_stop
(
struct
ath10k_htc
*
htc
);
void
ath10k_htc_destroy
(
struct
ath10k_htc
*
htc
);
struct
sk_buff
*
ath10k_htc_alloc_skb
(
int
size
);
#endif
drivers/net/wireless/ath/ath10k/htt.c
View file @
1f807827
...
...
@@ -16,6 +16,7 @@
*/
#include <linux/slab.h>
#include <linux/if_ether.h>
#include "htt.h"
#include "core.h"
...
...
@@ -36,7 +37,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
/* connect to control service */
conn_req
.
service_id
=
ATH10K_HTC_SVC_ID_HTT_DATA_MSG
;
status
=
ath10k_htc_connect_service
(
htt
->
ar
->
htc
,
&
conn_req
,
status
=
ath10k_htc_connect_service
(
&
htt
->
ar
->
htc
,
&
conn_req
,
&
conn_resp
);
if
(
status
)
...
...
@@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
return
0
;
}
struct
ath10k_htt
*
ath10k_htt_attach
(
struct
ath10k
*
ar
)
int
ath10k_htt_attach
(
struct
ath10k
*
ar
)
{
struct
ath10k_htt
*
htt
;
struct
ath10k_htt
*
htt
=
&
ar
->
htt
;
int
ret
;
htt
=
kzalloc
(
sizeof
(
*
htt
),
GFP_KERNEL
);
if
(
!
htt
)
return
NULL
;
htt
->
ar
=
ar
;
htt
->
max_throughput_mbps
=
800
;
...
...
@@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
* since ath10k_htt_rx_attach involves sending a rx ring configure
* message to the target.
*/
if
(
ath10k_htt_htc_attach
(
htt
))
ret
=
ath10k_htt_htc_attach
(
htt
);
if
(
ret
)
{
ath10k_err
(
"could not attach htt htc (%d)
\n
"
,
ret
);
goto
err_htc_attach
;
}
ret
=
ath10k_htt_tx_attach
(
htt
);
if
(
ret
)
{
...
...
@@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
goto
err_htc_attach
;
}
if
(
ath10k_htt_rx_attach
(
htt
))
ret
=
ath10k_htt_rx_attach
(
htt
);
if
(
ret
)
{
ath10k_err
(
"could not attach htt rx (%d)
\n
"
,
ret
);
goto
err_rx_attach
;
}
/*
* Prefetch enough data to satisfy target
...
...
@@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
8
+
/* llc snap */
2
;
/* ip4 dscp or ip6 priority */
return
htt
;
return
0
;
err_rx_attach:
ath10k_htt_tx_detach
(
htt
);
err_htc_attach:
kfree
(
htt
);
return
NULL
;
return
ret
;
}
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
...
...
@@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt)
{
ath10k_htt_rx_detach
(
htt
);
ath10k_htt_tx_detach
(
htt
);
kfree
(
htt
);
}
drivers/net/wireless/ath/ath10k/htt.h
View file @
1f807827
...
...
@@ -20,7 +20,6 @@
#include <linux/bug.h>
#include "core.h"
#include "htc.h"
#include "rx_desc.h"
...
...
@@ -1317,7 +1316,7 @@ struct htt_rx_desc {
#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7
/* 2^7 = 128 */
#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)
struct
ath10k_htt
*
ath10k_htt_attach
(
struct
ath10k
*
ar
);
int
ath10k_htt_attach
(
struct
ath10k
*
ar
);
int
ath10k_htt_attach_target
(
struct
ath10k_htt
*
htt
);
void
ath10k_htt_detach
(
struct
ath10k_htt
*
htt
);
...
...
drivers/net/wireless/ath/ath10k/htt_rx.c
View file @
1f807827
...
...
@@ -15,6 +15,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "htc.h"
#include "htt.h"
#include "txrx.h"
...
...
@@ -1036,7 +1037,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
void
ath10k_htt_t2h_msg_handler
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
{
struct
ath10k_htt
*
htt
=
ar
->
htt
;
struct
ath10k_htt
*
htt
=
&
ar
->
htt
;
struct
htt_resp
*
resp
=
(
struct
htt_resp
*
)
skb
->
data
;
/* confirm alignment */
...
...
drivers/net/wireless/ath/ath10k/htt_tx.c
View file @
1f807827
...
...
@@ -92,7 +92,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
/* At the beginning free queue number should hint us the maximum
* queue length */
pipe
=
htt
->
ar
->
htc
->
endpoint
[
htt
->
eid
].
ul_pipe_id
;
pipe
=
htt
->
ar
->
htc
.
endpoint
[
htt
->
eid
].
ul_pipe_id
;
htt
->
max_num_pending_tx
=
ath10k_hif_get_free_queue_number
(
htt
->
ar
,
pipe
);
...
...
@@ -153,7 +153,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt)
void
ath10k_htt_htc_tx_complete
(
struct
ath10k
*
ar
,
struct
sk_buff
*
skb
)
{
struct
ath10k_skb_cb
*
skb_cb
=
ATH10K_SKB_CB
(
skb
);
struct
ath10k_htt
*
htt
=
ar
->
htt
;
struct
ath10k_htt
*
htt
=
&
ar
->
htt
;
if
(
skb_cb
->
htt
.
is_conf
)
{
dev_kfree_skb_any
(
skb
);
...
...
@@ -194,7 +194,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
ATH10K_SKB_CB
(
skb
)
->
htt
.
is_conf
=
true
;
ret
=
ath10k_htc_send
(
htt
->
ar
->
htc
,
htt
->
eid
,
skb
);
ret
=
ath10k_htc_send
(
&
htt
->
ar
->
htc
,
htt
->
eid
,
skb
);
if
(
ret
)
{
dev_kfree_skb_any
(
skb
);
return
ret
;
...
...
@@ -281,7 +281,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
ATH10K_SKB_CB
(
skb
)
->
htt
.
is_conf
=
true
;
ret
=
ath10k_htc_send
(
htt
->
ar
->
htc
,
htt
->
eid
,
skb
);
ret
=
ath10k_htc_send
(
&
htt
->
ar
->
htc
,
htt
->
eid
,
skb
);
if
(
ret
)
{
dev_kfree_skb_any
(
skb
);
return
ret
;
...
...
@@ -346,7 +346,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb
->
htt
.
refcount
=
2
;
skb_cb
->
htt
.
msdu
=
msdu
;
res
=
ath10k_htc_send
(
htt
->
ar
->
htc
,
htt
->
eid
,
txdesc
);
res
=
ath10k_htc_send
(
&
htt
->
ar
->
htc
,
htt
->
eid
,
txdesc
);
if
(
res
)
goto
err
;
...
...
@@ -486,7 +486,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb
->
htt
.
txfrag
=
txfrag
;
skb_cb
->
htt
.
msdu
=
msdu
;
res
=
ath10k_htc_send
(
htt
->
ar
->
htc
,
htt
->
eid
,
txdesc
);
res
=
ath10k_htc_send
(
&
htt
->
ar
->
htc
,
htt
->
eid
,
txdesc
);
if
(
res
)
goto
err
;
...
...
drivers/net/wireless/ath/ath10k/mac.c
View file @
1f807827
...
...
@@ -20,6 +20,7 @@
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include "hif.h"
#include "core.h"
#include "debug.h"
#include "wmi.h"
...
...
@@ -43,6 +44,8 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
.
macaddr
=
macaddr
,
};
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
if
(
key
->
flags
&
IEEE80211_KEY_FLAG_PAIRWISE
)
arg
.
key_flags
=
WMI_KEY_PAIRWISE
;
else
...
...
@@ -87,6 +90,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
struct
ath10k
*
ar
=
arvif
->
ar
;
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
INIT_COMPLETION
(
ar
->
install_key_done
);
ret
=
ath10k_send_key
(
arvif
,
key
,
cmd
,
macaddr
);
...
...
@@ -327,6 +332,29 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
return
0
;
}
static
int
ath10k_mac_set_rts
(
struct
ath10k_vif
*
arvif
,
u32
value
)
{
if
(
value
!=
0xFFFFFFFF
)
value
=
min_t
(
u32
,
arvif
->
ar
->
hw
->
wiphy
->
rts_threshold
,
ATH10K_RTS_MAX
);
return
ath10k_wmi_vdev_set_param
(
arvif
->
ar
,
arvif
->
vdev_id
,
WMI_VDEV_PARAM_RTS_THRESHOLD
,
value
);
}
static
int
ath10k_mac_set_frag
(
struct
ath10k_vif
*
arvif
,
u32
value
)
{
if
(
value
!=
0xFFFFFFFF
)
value
=
clamp_t
(
u32
,
arvif
->
ar
->
hw
->
wiphy
->
frag_threshold
,
ATH10K_FRAGMT_THRESHOLD_MIN
,
ATH10K_FRAGMT_THRESHOLD_MAX
);
return
ath10k_wmi_vdev_set_param
(
arvif
->
ar
,
arvif
->
vdev_id
,
WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD
,
value
);
}
static
int
ath10k_peer_delete
(
struct
ath10k
*
ar
,
u32
vdev_id
,
const
u8
*
addr
)
{
int
ret
;
...
...
@@ -364,6 +392,20 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
spin_unlock_bh
(
&
ar
->
data_lock
);
}
static
void
ath10k_peer_cleanup_all
(
struct
ath10k
*
ar
)
{
struct
ath10k_peer
*
peer
,
*
tmp
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
spin_lock_bh
(
&
ar
->
data_lock
);
list_for_each_entry_safe
(
peer
,
tmp
,
&
ar
->
peers
,
list
)
{
list_del
(
&
peer
->
list
);
kfree
(
peer
);
}
spin_unlock_bh
(
&
ar
->
data_lock
);
}
/************************/
/* Interface management */
/************************/
...
...
@@ -372,6 +414,8 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
{
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
ret
=
wait_for_completion_timeout
(
&
ar
->
vdev_setup_done
,
ATH10K_VDEV_SETUP_TIMEOUT_HZ
);
if
(
ret
==
0
)
...
...
@@ -605,6 +649,8 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
{
int
ret
=
0
;
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
if
(
!
info
->
enable_beacon
)
{
ath10k_vdev_stop
(
arvif
);
return
;
...
...
@@ -631,6 +677,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
{
int
ret
=
0
;
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
if
(
!
info
->
ibss_joined
)
{
ret
=
ath10k_peer_delete
(
arvif
->
ar
,
arvif
->
vdev_id
,
self_peer
);
if
(
ret
)
...
...
@@ -680,6 +728,8 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
enum
wmi_sta_ps_mode
psmode
;
int
ret
;
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
if
(
vif
->
type
!=
NL80211_IFTYPE_STATION
)
return
;
...
...
@@ -722,6 +772,8 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
struct
ieee80211_bss_conf
*
bss_conf
,
struct
wmi_peer_assoc_complete_arg
*
arg
)
{
lockdep_assert_held
(
&
ar
->
conf_mutex
);
memcpy
(
arg
->
addr
,
sta
->
addr
,
ETH_ALEN
);
arg
->
vdev_id
=
arvif
->
vdev_id
;
arg
->
peer_aid
=
sta
->
aid
;
...
...
@@ -764,6 +816,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
const
u8
*
rsnie
=
NULL
;
const
u8
*
wpaie
=
NULL
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
bss
=
cfg80211_get_bss
(
ar
->
hw
->
wiphy
,
ar
->
hw
->
conf
.
chandef
.
chan
,
info
->
bssid
,
NULL
,
0
,
0
,
0
);
if
(
bss
)
{
...
...
@@ -804,6 +858,8 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar,
u32
ratemask
;
int
i
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
sband
=
ar
->
hw
->
wiphy
->
bands
[
ar
->
hw
->
conf
.
chandef
.
chan
->
band
];
ratemask
=
sta
->
supp_rates
[
ar
->
hw
->
conf
.
chandef
.
chan
->
band
];
rates
=
sband
->
bitrates
;
...
...
@@ -827,6 +883,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
int
smps
;
int
i
,
n
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
!
ht_cap
->
ht_supported
)
return
;
...
...
@@ -905,6 +963,8 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
u32
uapsd
=
0
;
u32
max_sp
=
0
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
sta
->
wme
)
arg
->
peer_flags
|=
WMI_PEER_QOS
;
...
...
@@ -1056,6 +1116,8 @@ static int ath10k_peer_assoc(struct ath10k *ar,
{
struct
wmi_peer_assoc_complete_arg
arg
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
memset
(
&
arg
,
0
,
sizeof
(
struct
wmi_peer_assoc_complete_arg
));
ath10k_peer_assoc_h_basic
(
ar
,
arvif
,
sta
,
bss_conf
,
&
arg
);
...
...
@@ -1079,6 +1141,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct
ieee80211_sta
*
ap_sta
;
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
rcu_read_lock
();
ap_sta
=
ieee80211_find_sta
(
vif
,
bss_conf
->
bssid
);
...
...
@@ -1119,6 +1183,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
struct
ath10k_vif
*
arvif
=
ath10k_vif_to_arvif
(
vif
);
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
/*
* For some reason, calling VDEV-DOWN before VDEV-STOP
* makes the FW to send frames via HTT after disassociation.
...
...
@@ -1152,6 +1218,8 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
{
int
ret
=
0
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
ret
=
ath10k_peer_assoc
(
ar
,
arvif
,
sta
,
NULL
);
if
(
ret
)
{
ath10k_warn
(
"WMI peer assoc failed for %pM
\n
"
,
sta
->
addr
);
...
...
@@ -1172,6 +1240,8 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
{
int
ret
=
0
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
ret
=
ath10k_clear_peer_keys
(
arvif
,
sta
->
addr
);
if
(
ret
)
{
ath10k_warn
(
"could not clear all peer wep keys (%d)
\n
"
,
ret
);
...
...
@@ -1198,6 +1268,8 @@ static int ath10k_update_channel_list(struct ath10k *ar)
int
ret
;
int
i
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
bands
=
hw
->
wiphy
->
bands
;
for
(
band
=
0
;
band
<
IEEE80211_NUM_BANDS
;
band
++
)
{
if
(
!
bands
[
band
])
...
...
@@ -1276,21 +1348,19 @@ static int ath10k_update_channel_list(struct ath10k *ar)
return
ret
;
}
static
void
ath10k_reg_notifier
(
struct
wiphy
*
wiphy
,
struct
regulatory_request
*
request
)
static
void
ath10k_regd_update
(
struct
ath10k
*
ar
)
{
struct
ieee80211_hw
*
hw
=
wiphy_to_ieee80211_hw
(
wiphy
);
struct
reg_dmn_pair_mapping
*
regpair
;
struct
ath10k
*
ar
=
hw
->
priv
;
int
ret
;
ath_reg_notifier_apply
(
wiphy
,
request
,
&
ar
->
ath_common
.
regulatory
);
lockdep_assert_held
(
&
ar
->
conf_mutex
);
ret
=
ath10k_update_channel_list
(
ar
);
if
(
ret
)
ath10k_warn
(
"could not update channel list (%d)
\n
"
,
ret
);
regpair
=
ar
->
ath_common
.
regulatory
.
regpair
;
/* Target allows setting up per-band regdomain but ath_common provides
* a combined one only */
ret
=
ath10k_wmi_pdev_set_regdomain
(
ar
,
...
...
@@ -1303,6 +1373,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
ath10k_warn
(
"could not set pdev regdomain (%d)
\n
"
,
ret
);
}
static
void
ath10k_reg_notifier
(
struct
wiphy
*
wiphy
,
struct
regulatory_request
*
request
)
{
struct
ieee80211_hw
*
hw
=
wiphy_to_ieee80211_hw
(
wiphy
);
struct
ath10k
*
ar
=
hw
->
priv
;
ath_reg_notifier_apply
(
wiphy
,
request
,
&
ar
->
ath_common
.
regulatory
);
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
==
ATH10K_STATE_ON
)
ath10k_regd_update
(
ar
);
mutex_unlock
(
&
ar
->
conf_mutex
);
}
/***************/
/* TX handlers */
/***************/
...
...
@@ -1397,15 +1481,15 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
int
ret
;
if
(
ieee80211_is_mgmt
(
hdr
->
frame_control
))
ret
=
ath10k_htt_mgmt_tx
(
ar
->
htt
,
skb
);
ret
=
ath10k_htt_mgmt_tx
(
&
ar
->
htt
,
skb
);
else
if
(
ieee80211_is_nullfunc
(
hdr
->
frame_control
))
/* FW does not report tx status properly for NullFunc frames
* unless they are sent through mgmt tx path. mac80211 sends
* those frames when it detects link/beacon loss and depends on
* the tx status to be correct. */
ret
=
ath10k_htt_mgmt_tx
(
ar
->
htt
,
skb
);
ret
=
ath10k_htt_mgmt_tx
(
&
ar
->
htt
,
skb
);
else
ret
=
ath10k_htt_tx
(
ar
->
htt
,
skb
);
ret
=
ath10k_htt_tx
(
&
ar
->
htt
,
skb
);
if
(
ret
)
{
ath10k_warn
(
"tx failed (%d). dropping packet.
\n
"
,
ret
);
...
...
@@ -1552,6 +1636,10 @@ static int ath10k_abort_scan(struct ath10k *ar)
ret
=
ath10k_wmi_stop_scan
(
ar
,
&
arg
);
if
(
ret
)
{
ath10k_warn
(
"could not submit wmi stop scan (%d)
\n
"
,
ret
);
spin_lock_bh
(
&
ar
->
data_lock
);
ar
->
scan
.
in_progress
=
false
;
ath10k_offchan_tx_purge
(
ar
);
spin_unlock_bh
(
&
ar
->
data_lock
);
return
-
EIO
;
}
...
...
@@ -1645,10 +1733,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,
tid
=
qc
[
0
]
&
IEEE80211_QOS_CTL_TID_MASK
;
}
/* it makes no sense to process injected frames like that */
if
(
info
->
control
.
vif
&&
info
->
control
.
vif
->
type
!=
NL80211_IFTYPE_MONITOR
)
{
ath10k_tx_h_qos_workaround
(
hw
,
control
,
skb
);
ath10k_tx_h_update_wep_key
(
skb
);
ath10k_tx_h_add_p2p_noa_ie
(
ar
,
skb
);
ath10k_tx_h_seq_no
(
skb
);
}
memset
(
ATH10K_SKB_CB
(
skb
),
0
,
sizeof
(
*
ATH10K_SKB_CB
(
skb
)));
ATH10K_SKB_CB
(
skb
)
->
htt
.
vdev_id
=
vdev_id
;
...
...
@@ -1673,10 +1765,57 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/*
* Initialize various parameters with default vaules.
*/
void
ath10k_halt
(
struct
ath10k
*
ar
)
{
lockdep_assert_held
(
&
ar
->
conf_mutex
);
del_timer_sync
(
&
ar
->
scan
.
timeout
);
ath10k_offchan_tx_purge
(
ar
);
ath10k_peer_cleanup_all
(
ar
);
ath10k_core_stop
(
ar
);
ath10k_hif_power_down
(
ar
);
spin_lock_bh
(
&
ar
->
data_lock
);
if
(
ar
->
scan
.
in_progress
)
{
del_timer
(
&
ar
->
scan
.
timeout
);
ar
->
scan
.
in_progress
=
false
;
ieee80211_scan_completed
(
ar
->
hw
,
true
);
}
spin_unlock_bh
(
&
ar
->
data_lock
);
}
static
int
ath10k_start
(
struct
ieee80211_hw
*
hw
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
int
ret
;
int
ret
=
0
;
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
!=
ATH10K_STATE_OFF
&&
ar
->
state
!=
ATH10K_STATE_RESTARTING
)
{
ret
=
-
EINVAL
;
goto
exit
;
}
ret
=
ath10k_hif_power_up
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not init hif (%d)
\n
"
,
ret
);
ar
->
state
=
ATH10K_STATE_OFF
;
goto
exit
;
}
ret
=
ath10k_core_start
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not init core (%d)
\n
"
,
ret
);
ath10k_hif_power_down
(
ar
);
ar
->
state
=
ATH10K_STATE_OFF
;
goto
exit
;
}
if
(
ar
->
state
==
ATH10K_STATE_OFF
)
ar
->
state
=
ATH10K_STATE_ON
;
else
if
(
ar
->
state
==
ATH10K_STATE_RESTARTING
)
ar
->
state
=
ATH10K_STATE_RESTARTED
;
ret
=
ath10k_wmi_pdev_set_param
(
ar
,
WMI_PDEV_PARAM_PMF_QOS
,
1
);
if
(
ret
)
...
...
@@ -1688,6 +1827,10 @@ static int ath10k_start(struct ieee80211_hw *hw)
ath10k_warn
(
"could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)
\n
"
,
ret
);
ath10k_regd_update
(
ar
);
exit:
mutex_unlock
(
&
ar
->
conf_mutex
);
return
0
;
}
...
...
@@ -1695,18 +1838,48 @@ static void ath10k_stop(struct ieee80211_hw *hw)
{
struct
ath10k
*
ar
=
hw
->
priv
;
/* avoid leaks in case FW never confirms scan for offchannel */
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
==
ATH10K_STATE_ON
||
ar
->
state
==
ATH10K_STATE_RESTARTED
||
ar
->
state
==
ATH10K_STATE_WEDGED
)
ath10k_halt
(
ar
);
ar
->
state
=
ATH10K_STATE_OFF
;
mutex_unlock
(
&
ar
->
conf_mutex
);
cancel_work_sync
(
&
ar
->
offchan_tx_work
);
ath10k_offchan_tx_purge
(
ar
);
cancel_work_sync
(
&
ar
->
restart_work
);
}
static
int
ath10k_config
(
struct
ieee80211_hw
*
hw
,
u32
changed
)
static
void
ath10k_config_ps
(
struct
ath10k
*
ar
)
{
struct
ath10k_generic_iter
ar_iter
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
/* During HW reconfiguration mac80211 reports all interfaces that were
* running until reconfiguration was started. Since FW doesn't have any
* vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */
if
(
ar
->
state
==
ATH10K_STATE_RESTARTED
)
return
;
memset
(
&
ar_iter
,
0
,
sizeof
(
struct
ath10k_generic_iter
));
ar_iter
.
ar
=
ar
;
ieee80211_iterate_active_interfaces_atomic
(
ar
->
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
ath10k_ps_iter
,
&
ar_iter
);
if
(
ar_iter
.
ret
)
ath10k_warn
(
"failed to set ps config (%d)
\n
"
,
ar_iter
.
ret
);
}
static
int
ath10k_config
(
struct
ieee80211_hw
*
hw
,
u32
changed
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
struct
ieee80211_conf
*
conf
=
&
hw
->
conf
;
int
ret
=
0
;
u32
flags
;
mutex_lock
(
&
ar
->
conf_mutex
);
...
...
@@ -1718,18 +1891,8 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_bh
(
&
ar
->
data_lock
);
}
if
(
changed
&
IEEE80211_CONF_CHANGE_PS
)
{
memset
(
&
ar_iter
,
0
,
sizeof
(
struct
ath10k_generic_iter
));
ar_iter
.
ar
=
ar
;
flags
=
IEEE80211_IFACE_ITER_RESUME_ALL
;
ieee80211_iterate_active_interfaces_atomic
(
hw
,
flags
,
ath10k_ps_iter
,
&
ar_iter
);
ret
=
ar_iter
.
ret
;
}
if
(
changed
&
IEEE80211_CONF_CHANGE_PS
)
ath10k_config_ps
(
ar
);
if
(
changed
&
IEEE80211_CONF_CHANGE_MONITOR
)
{
if
(
conf
->
flags
&
IEEE80211_CONF_MONITOR
)
...
...
@@ -1738,6 +1901,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
ret
=
ath10k_monitor_destroy
(
ar
);
}
ath10k_wmi_flush_tx
(
ar
);
mutex_unlock
(
&
ar
->
conf_mutex
);
return
ret
;
}
...
...
@@ -1859,6 +2023,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ath10k_warn
(
"Failed to set PSPOLL count: %d
\n
"
,
ret
);
}
ret
=
ath10k_mac_set_rts
(
arvif
,
ar
->
hw
->
wiphy
->
rts_threshold
);
if
(
ret
)
ath10k_warn
(
"failed to set rts threshold for vdev %d (%d)
\n
"
,
arvif
->
vdev_id
,
ret
);
ret
=
ath10k_mac_set_frag
(
arvif
,
ar
->
hw
->
wiphy
->
frag_threshold
);
if
(
ret
)
ath10k_warn
(
"failed to set frag threshold for vdev %d (%d)
\n
"
,
arvif
->
vdev_id
,
ret
);
if
(
arvif
->
vdev_type
==
WMI_VDEV_TYPE_MONITOR
)
ar
->
monitor_present
=
true
;
...
...
@@ -2363,6 +2537,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
u32
value
=
0
;
int
ret
=
0
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_STA
)
return
0
;
...
...
@@ -2558,11 +2734,16 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct
ath10k_vif
*
arvif
=
ath10k_vif_to_arvif
(
vif
);
u32
rts
=
ar_iter
->
ar
->
hw
->
wiphy
->
rts_threshold
;
rts
=
min_t
(
u32
,
rts
,
ATH10K_RTS_MAX
);
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
ar_iter
->
ret
=
ath10k_wmi_vdev_set_param
(
ar_iter
->
ar
,
arvif
->
vdev_id
,
WMI_VDEV_PARAM_RTS_THRESHOLD
,
rts
);
/* During HW reconfiguration mac80211 reports all interfaces that were
* running until reconfiguration was started. Since FW doesn't have any
* vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */
if
(
ar_iter
->
ar
->
state
==
ATH10K_STATE_RESTARTED
)
return
;
ar_iter
->
ret
=
ath10k_mac_set_rts
(
arvif
,
rts
);
if
(
ar_iter
->
ret
)
ath10k_warn
(
"Failed to set RTS threshold for VDEV: %d
\n
"
,
arvif
->
vdev_id
);
...
...
@@ -2581,7 +2762,8 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
ar_iter
.
ar
=
ar
;
mutex_lock
(
&
ar
->
conf_mutex
);
ieee80211_iterate_active_interfaces
(
hw
,
IEEE80211_IFACE_ITER_RESUME_ALL
,
ieee80211_iterate_active_interfaces_atomic
(
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
ath10k_set_rts_iter
,
&
ar_iter
);
mutex_unlock
(
&
ar
->
conf_mutex
);
...
...
@@ -2593,17 +2775,17 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct
ath10k_generic_iter
*
ar_iter
=
data
;
struct
ath10k_vif
*
arvif
=
ath10k_vif_to_arvif
(
vif
);
u32
frag
=
ar_iter
->
ar
->
hw
->
wiphy
->
frag_threshold
;
int
ret
;
frag
=
clamp_t
(
u32
,
frag
,
ATH10K_FRAGMT_THRESHOLD_MIN
,
ATH10K_FRAGMT_THRESHOLD_MAX
);
lockdep_assert_held
(
&
arvif
->
ar
->
conf_mutex
);
ret
=
ath10k_wmi_vdev_set_param
(
ar_iter
->
ar
,
arvif
->
vdev_id
,
WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD
,
frag
);
/* During HW reconfiguration mac80211 reports all interfaces that were
* running until reconfiguration was started. Since FW doesn't have any
* vdevs at this point we must not iterate over this interface list.
* This setting will be updated upon add_interface(). */
if
(
ar_iter
->
ar
->
state
==
ATH10K_STATE_RESTARTED
)
return
;
ar_iter
->
ret
=
ret
;
ar_iter
->
ret
=
ath10k_mac_set_frag
(
arvif
,
frag
)
;
if
(
ar_iter
->
ret
)
ath10k_warn
(
"Failed to set frag threshold for VDEV: %d
\n
"
,
arvif
->
vdev_id
);
...
...
@@ -2622,7 +2804,8 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
ar_iter
.
ar
=
ar
;
mutex_lock
(
&
ar
->
conf_mutex
);
ieee80211_iterate_active_interfaces
(
hw
,
IEEE80211_IFACE_ITER_RESUME_ALL
,
ieee80211_iterate_active_interfaces_atomic
(
hw
,
IEEE80211_IFACE_ITER_NORMAL
,
ath10k_set_frag_iter
,
&
ar_iter
);
mutex_unlock
(
&
ar
->
conf_mutex
);
...
...
@@ -2632,6 +2815,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
static
void
ath10k_flush
(
struct
ieee80211_hw
*
hw
,
u32
queues
,
bool
drop
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
bool
skip
;
int
ret
;
/* mac80211 doesn't care if we really xmit queued frames or not
...
...
@@ -2639,16 +2823,29 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
if
(
drop
)
return
;
ret
=
wait_event_timeout
(
ar
->
htt
->
empty_tx_wq
,
({
mutex_lock
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
==
ATH10K_STATE_WEDGED
)
goto
skip
;
ret
=
wait_event_timeout
(
ar
->
htt
.
empty_tx_wq
,
({
bool
empty
;
spin_lock_bh
(
&
ar
->
htt
->
tx_lock
);
empty
=
bitmap_empty
(
ar
->
htt
->
used_msdu_ids
,
ar
->
htt
->
max_num_pending_tx
);
spin_unlock_bh
(
&
ar
->
htt
->
tx_lock
);
(
empty
);
spin_lock_bh
(
&
ar
->
htt
.
tx_lock
);
empty
=
bitmap_empty
(
ar
->
htt
.
used_msdu_ids
,
ar
->
htt
.
max_num_pending_tx
);
spin_unlock_bh
(
&
ar
->
htt
.
tx_lock
);
skip
=
(
ar
->
state
==
ATH10K_STATE_WEDGED
);
(
empty
||
skip
);
}),
ATH10K_FLUSH_TIMEOUT_HZ
);
if
(
ret
<=
0
)
if
(
ret
<=
0
||
skip
)
ath10k_warn
(
"tx not flushed
\n
"
);
skip:
mutex_unlock
(
&
ar
->
conf_mutex
);
}
/* TODO: Implement this function properly
...
...
@@ -2660,6 +2857,83 @@ static int ath10k_tx_last_beacon(struct ieee80211_hw *hw)
return
1
;
}
#ifdef CONFIG_PM
static
int
ath10k_suspend
(
struct
ieee80211_hw
*
hw
,
struct
cfg80211_wowlan
*
wowlan
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
int
ret
;
ar
->
is_target_paused
=
false
;
ret
=
ath10k_wmi_pdev_suspend_target
(
ar
);
if
(
ret
)
{
ath10k_warn
(
"could not suspend target (%d)
\n
"
,
ret
);
return
1
;
}
ret
=
wait_event_interruptible_timeout
(
ar
->
event_queue
,
ar
->
is_target_paused
==
true
,
1
*
HZ
);
if
(
ret
<
0
)
{
ath10k_warn
(
"suspend interrupted (%d)
\n
"
,
ret
);
goto
resume
;
}
else
if
(
ret
==
0
)
{
ath10k_warn
(
"suspend timed out - target pause event never came
\n
"
);
goto
resume
;
}
ret
=
ath10k_hif_suspend
(
ar
);
if
(
ret
)
{
ath10k_warn
(
"could not suspend hif (%d)
\n
"
,
ret
);
goto
resume
;
}
return
0
;
resume:
ret
=
ath10k_wmi_pdev_resume_target
(
ar
);
if
(
ret
)
ath10k_warn
(
"could not resume target (%d)
\n
"
,
ret
);
return
1
;
}
static
int
ath10k_resume
(
struct
ieee80211_hw
*
hw
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
int
ret
;
ret
=
ath10k_hif_resume
(
ar
);
if
(
ret
)
{
ath10k_warn
(
"could not resume hif (%d)
\n
"
,
ret
);
return
1
;
}
ret
=
ath10k_wmi_pdev_resume_target
(
ar
);
if
(
ret
)
{
ath10k_warn
(
"could not resume target (%d)
\n
"
,
ret
);
return
1
;
}
return
0
;
}
#endif
static
void
ath10k_restart_complete
(
struct
ieee80211_hw
*
hw
)
{
struct
ath10k
*
ar
=
hw
->
priv
;
mutex_lock
(
&
ar
->
conf_mutex
);
/* If device failed to restart it will be in a different state, e.g.
* ATH10K_STATE_WEDGED */
if
(
ar
->
state
==
ATH10K_STATE_RESTARTED
)
{
ath10k_info
(
"device successfully recovered
\n
"
);
ar
->
state
=
ATH10K_STATE_ON
;
}
mutex_unlock
(
&
ar
->
conf_mutex
);
}
static
const
struct
ieee80211_ops
ath10k_ops
=
{
.
tx
=
ath10k_tx
,
.
start
=
ath10k_start
,
...
...
@@ -2680,6 +2954,11 @@ static const struct ieee80211_ops ath10k_ops = {
.
set_frag_threshold
=
ath10k_set_frag_threshold
,
.
flush
=
ath10k_flush
,
.
tx_last_beacon
=
ath10k_tx_last_beacon
,
.
restart_complete
=
ath10k_restart_complete
,
#ifdef CONFIG_PM
.
suspend
=
ath10k_suspend
,
.
resume
=
ath10k_resume
,
#endif
};
#define RATETAB_ENT(_rate, _rateid, _flags) { \
...
...
@@ -2948,8 +3227,10 @@ int ath10k_mac_register(struct ath10k *ar)
channels
=
kmemdup
(
ath10k_2ghz_channels
,
sizeof
(
ath10k_2ghz_channels
),
GFP_KERNEL
);
if
(
!
channels
)
return
-
ENOMEM
;
if
(
!
channels
)
{
ret
=
-
ENOMEM
;
goto
err_free
;
}
band
=
&
ar
->
mac
.
sbands
[
IEEE80211_BAND_2GHZ
];
band
->
n_channels
=
ARRAY_SIZE
(
ath10k_2ghz_channels
);
...
...
@@ -2968,11 +3249,8 @@ int ath10k_mac_register(struct ath10k *ar)
sizeof
(
ath10k_5ghz_channels
),
GFP_KERNEL
);
if
(
!
channels
)
{
if
(
ar
->
phy_capability
&
WHAL_WLAN_11G_CAPABILITY
)
{
band
=
&
ar
->
mac
.
sbands
[
IEEE80211_BAND_2GHZ
];
kfree
(
band
->
channels
);
}
return
-
ENOMEM
;
ret
=
-
ENOMEM
;
goto
err_free
;
}
band
=
&
ar
->
mac
.
sbands
[
IEEE80211_BAND_5GHZ
];
...
...
@@ -3036,25 +3314,30 @@ int ath10k_mac_register(struct ath10k *ar)
ath10k_reg_notifier
);
if
(
ret
)
{
ath10k_err
(
"Regulatory initialization failed
\n
"
);
return
ret
;
goto
err_free
;
}
ret
=
ieee80211_register_hw
(
ar
->
hw
);
if
(
ret
)
{
ath10k_err
(
"ieee80211 registration failed: %d
\n
"
,
ret
);
return
ret
;
goto
err_free
;
}
if
(
!
ath_is_world_regd
(
&
ar
->
ath_common
.
regulatory
))
{
ret
=
regulatory_hint
(
ar
->
hw
->
wiphy
,
ar
->
ath_common
.
regulatory
.
alpha2
);
if
(
ret
)
goto
e
xit
;
goto
e
rr_unregister
;
}
return
0
;
exit:
err_unregister:
ieee80211_unregister_hw
(
ar
->
hw
);
err_free:
kfree
(
ar
->
mac
.
sbands
[
IEEE80211_BAND_2GHZ
].
channels
);
kfree
(
ar
->
mac
.
sbands
[
IEEE80211_BAND_5GHZ
].
channels
);
return
ret
;
}
...
...
drivers/net/wireless/ath/ath10k/mac.h
View file @
1f807827
...
...
@@ -34,6 +34,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
void
ath10k_reset_scan
(
unsigned
long
ptr
);
void
ath10k_offchan_tx_purge
(
struct
ath10k
*
ar
);
void
ath10k_offchan_tx_work
(
struct
work_struct
*
work
);
void
ath10k_halt
(
struct
ath10k
*
ar
);
static
inline
struct
ath10k_vif
*
ath10k_vif_to_arvif
(
struct
ieee80211_vif
*
vif
)
{
...
...
drivers/net/wireless/ath/ath10k/pci.c
View file @
1f807827
...
...
@@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
int
num
);
static
void
ath10k_pci_rx_pipe_cleanup
(
struct
hif_ce_pipe_info
*
pipe_info
);
static
void
ath10k_pci_stop_ce
(
struct
ath10k
*
ar
);
static
void
ath10k_pci_device_reset
(
struct
ath10k
*
ar
);
static
int
ath10k_pci_reset_target
(
struct
ath10k
*
ar
);
static
const
struct
ce_attr
host_ce_config_wlan
[]
=
{
/* host->target HTC control and raw streams */
...
...
@@ -718,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
reg_dump_values
[
i
+
1
],
reg_dump_values
[
i
+
2
],
reg_dump_values
[
i
+
3
]);
ieee80211_queue_work
(
ar
->
hw
,
&
ar
->
restart_work
);
}
static
void
ath10k_pci_hif_send_complete_check
(
struct
ath10k
*
ar
,
u8
pipe
,
...
...
@@ -744,7 +748,7 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
ath10k_ce_per_engine_service
(
ar
,
pipe
);
}
static
void
ath10k_pci_hif_
post_init
(
struct
ath10k
*
ar
,
static
void
ath10k_pci_hif_
set_callbacks
(
struct
ath10k
*
ar
,
struct
ath10k_hif_cb
*
callbacks
)
{
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
...
...
@@ -1263,7 +1267,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_process_ce
(
ar
);
ath10k_pci_cleanup_ce
(
ar
);
ath10k_pci_buffer_cleanup
(
ar
);
ath10k_pci_ce_deinit
(
ar
);
}
static
int
ath10k_pci_hif_exchange_bmi_msg
(
struct
ath10k
*
ar
,
...
...
@@ -1735,6 +1738,115 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
ath10k_pci_sleep
(
ar
);
}
static
int
ath10k_pci_hif_power_up
(
struct
ath10k
*
ar
)
{
int
ret
;
/*
* Bring the target up cleanly.
*
* The target may be in an undefined state with an AUX-powered Target
* and a Host in WoW mode. If the Host crashes, loses power, or is
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/
ath10k_pci_device_reset
(
ar
);
ret
=
ath10k_pci_reset_target
(
ar
);
if
(
ret
)
goto
err
;
if
(
ath10k_target_ps
)
{
ath10k_dbg
(
ATH10K_DBG_PCI
,
"on-chip power save enabled
\n
"
);
}
else
{
/* Force AWAKE forever */
ath10k_dbg
(
ATH10K_DBG_PCI
,
"on-chip power save disabled
\n
"
);
ath10k_do_pci_wake
(
ar
);
}
ret
=
ath10k_pci_ce_init
(
ar
);
if
(
ret
)
goto
err_ps
;
ret
=
ath10k_pci_init_config
(
ar
);
if
(
ret
)
goto
err_ce
;
ret
=
ath10k_pci_wake_target_cpu
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not wake up target CPU (%d)
\n
"
,
ret
);
goto
err_ce
;
}
return
0
;
err_ce:
ath10k_pci_ce_deinit
(
ar
);
err_ps:
if
(
!
ath10k_target_ps
)
ath10k_do_pci_sleep
(
ar
);
err:
return
ret
;
}
static
void
ath10k_pci_hif_power_down
(
struct
ath10k
*
ar
)
{
ath10k_pci_ce_deinit
(
ar
);
if
(
!
ath10k_target_ps
)
ath10k_do_pci_sleep
(
ar
);
}
#ifdef CONFIG_PM
#define ATH10K_PCI_PM_CONTROL 0x44
static
int
ath10k_pci_hif_suspend
(
struct
ath10k
*
ar
)
{
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
struct
pci_dev
*
pdev
=
ar_pci
->
pdev
;
u32
val
;
pci_read_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
&
val
);
if
((
val
&
0x000000ff
)
!=
0x3
)
{
pci_save_state
(
pdev
);
pci_disable_device
(
pdev
);
pci_write_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
(
val
&
0xffffff00
)
|
0x03
);
}
return
0
;
}
static
int
ath10k_pci_hif_resume
(
struct
ath10k
*
ar
)
{
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
struct
pci_dev
*
pdev
=
ar_pci
->
pdev
;
u32
val
;
pci_read_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
&
val
);
if
((
val
&
0x000000ff
)
!=
0
)
{
pci_restore_state
(
pdev
);
pci_write_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
val
&
0xffffff00
);
/*
* Suspend/Resume resets the PCI configuration space,
* so we have to re-disable the RETRY_TIMEOUT register (0x41)
* to keep PCI Tx retries from interfering with C3 CPU state
*/
pci_read_config_dword
(
pdev
,
0x40
,
&
val
);
if
((
val
&
0x0000ff00
)
!=
0
)
pci_write_config_dword
(
pdev
,
0x40
,
val
&
0xffff00ff
);
}
return
0
;
}
#endif
static
const
struct
ath10k_hif_ops
ath10k_pci_hif_ops
=
{
.
send_head
=
ath10k_pci_hif_send_head
,
.
exchange_bmi_msg
=
ath10k_pci_hif_exchange_bmi_msg
,
...
...
@@ -1743,8 +1855,14 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
.
map_service_to_pipe
=
ath10k_pci_hif_map_service_to_pipe
,
.
get_default_pipe
=
ath10k_pci_hif_get_default_pipe
,
.
send_complete_check
=
ath10k_pci_hif_send_complete_check
,
.
init
=
ath10k_pci_hif_post_init
,
.
set_callbacks
=
ath10k_pci_hif_set_callbacks
,
.
get_free_queue_number
=
ath10k_pci_hif_get_free_queue_number
,
.
power_up
=
ath10k_pci_hif_power_up
,
.
power_down
=
ath10k_pci_hif_power_down
,
#ifdef CONFIG_PM
.
suspend
=
ath10k_pci_hif_suspend
,
.
resume
=
ath10k_pci_hif_resume
,
#endif
};
static
void
ath10k_pci_ce_tasklet
(
unsigned
long
ptr
)
...
...
@@ -2059,9 +2177,9 @@ static int ath10k_pci_reset_target(struct ath10k *ar)
return
0
;
}
static
void
ath10k_pci_device_reset
(
struct
ath10k
_pci
*
ar_pci
)
static
void
ath10k_pci_device_reset
(
struct
ath10k
*
ar
)
{
struct
ath10k
*
ar
=
ar_pci
->
ar
;
struct
ath10k
_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
)
;
void
__iomem
*
mem
=
ar_pci
->
mem
;
int
i
;
u32
val
;
...
...
@@ -2118,7 +2236,7 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
case
ATH10K_PCI_FEATURE_MSI_X
:
ath10k_dbg
(
ATH10K_DBG_PCI
,
"device supports MSI-X
\n
"
);
break
;
case
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
:
case
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
:
ath10k_dbg
(
ATH10K_DBG_PCI
,
"QCA988X_1.0 workaround enabled
\n
"
);
break
;
}
...
...
@@ -2145,7 +2263,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
switch
(
pci_dev
->
device
)
{
case
QCA988X_1_0_DEVICE_ID
:
set_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
,
ar_pci
->
features
);
set_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
,
ar_pci
->
features
);
break
;
case
QCA988X_2_0_DEVICE_ID
:
set_bit
(
ATH10K_PCI_FEATURE_MSI_X
,
ar_pci
->
features
);
...
...
@@ -2158,8 +2276,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ath10k_pci_dump_features
(
ar_pci
);
ar
=
ath10k_core_create
(
ar_pci
,
ar_pci
->
dev
,
ATH10K_BUS_PCI
,
&
ath10k_pci_hif_ops
);
ar
=
ath10k_core_create
(
ar_pci
,
ar_pci
->
dev
,
&
ath10k_pci_hif_ops
);
if
(
!
ar
)
{
ath10k_err
(
"ath10k_core_create failed!
\n
"
);
ret
=
-
EINVAL
;
...
...
@@ -2167,7 +2284,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
}
/* Enable QCA988X_1.0 HW workarounds */
if
(
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
,
ar_pci
->
features
))
if
(
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
,
ar_pci
->
features
))
spin_lock_init
(
&
ar_pci
->
hw_v1_workaround_lock
);
ar_pci
->
ar
=
ar
;
...
...
@@ -2247,54 +2364,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto
err_iomap
;
}
/*
* Bring the target up cleanly.
*
* The target may be in an undefined state with an AUX-powered Target
* and a Host in WoW mode. If the Host crashes, loses power, or is
* restarted (without unloading the driver) then the Target is left
* (aux) powered and running. On a subsequent driver load, the Target
* is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe.
*/
ath10k_pci_device_reset
(
ar_pci
);
ret
=
ath10k_pci_reset_target
(
ar
);
if
(
ret
)
goto
err_intr
;
if
(
ath10k_target_ps
)
{
ath10k_dbg
(
ATH10K_DBG_PCI
,
"on-chip power save enabled
\n
"
);
}
else
{
/* Force AWAKE forever */
ath10k_dbg
(
ATH10K_DBG_PCI
,
"on-chip power save disabled
\n
"
);
ath10k_do_pci_wake
(
ar
);
}
ret
=
ath10k_pci_ce_init
(
ar
);
if
(
ret
)
goto
err_intr
;
ret
=
ath10k_pci_init_config
(
ar
);
if
(
ret
)
goto
err_ce
;
ret
=
ath10k_pci_wake_target_cpu
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not wake up target CPU (%d)
\n
"
,
ret
);
goto
err_ce
;
}
ret
=
ath10k_core_register
(
ar
);
if
(
ret
)
{
ath10k_err
(
"could not register driver core (%d)
\n
"
,
ret
);
goto
err_
ce
;
goto
err_
intr
;
}
return
0
;
err_ce:
ath10k_pci_ce_deinit
(
ar
);
err_intr:
ath10k_pci_stop_intr
(
ar
);
err_iomap:
...
...
@@ -2345,128 +2422,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
kfree
(
ar_pci
);
}
#if defined(CONFIG_PM_SLEEP)
#define ATH10K_PCI_PM_CONTROL 0x44
static
int
ath10k_pci_suspend
(
struct
device
*
device
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
device
);
struct
ath10k
*
ar
=
pci_get_drvdata
(
pdev
);
struct
ath10k_pci
*
ar_pci
;
u32
val
;
int
ret
,
retval
;
ath10k_dbg
(
ATH10K_DBG_PCI
,
"%s
\n
"
,
__func__
);
if
(
!
ar
)
return
-
ENODEV
;
ar_pci
=
ath10k_pci_priv
(
ar
);
if
(
!
ar_pci
)
return
-
ENODEV
;
if
(
ath10k_core_target_suspend
(
ar
))
return
-
EBUSY
;
ret
=
wait_event_interruptible_timeout
(
ar
->
event_queue
,
ar
->
is_target_paused
==
true
,
1
*
HZ
);
if
(
ret
<
0
)
{
ath10k_warn
(
"suspend interrupted (%d)
\n
"
,
ret
);
retval
=
ret
;
goto
resume
;
}
else
if
(
ret
==
0
)
{
ath10k_warn
(
"suspend timed out - target pause event never came
\n
"
);
retval
=
EIO
;
goto
resume
;
}
/*
* reset is_target_paused and host can check that in next time,
* or it will always be TRUE and host just skip the waiting
* condition, it causes target assert due to host already
* suspend
*/
ar
->
is_target_paused
=
false
;
pci_read_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
&
val
);
if
((
val
&
0x000000ff
)
!=
0x3
)
{
pci_save_state
(
pdev
);
pci_disable_device
(
pdev
);
pci_write_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
(
val
&
0xffffff00
)
|
0x03
);
}
return
0
;
resume:
ret
=
ath10k_core_target_resume
(
ar
);
if
(
ret
)
ath10k_warn
(
"could not resume (%d)
\n
"
,
ret
);
return
retval
;
}
static
int
ath10k_pci_resume
(
struct
device
*
device
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
device
);
struct
ath10k
*
ar
=
pci_get_drvdata
(
pdev
);
struct
ath10k_pci
*
ar_pci
;
int
ret
;
u32
val
;
ath10k_dbg
(
ATH10K_DBG_PCI
,
"%s
\n
"
,
__func__
);
if
(
!
ar
)
return
-
ENODEV
;
ar_pci
=
ath10k_pci_priv
(
ar
);
if
(
!
ar_pci
)
return
-
ENODEV
;
ret
=
pci_enable_device
(
pdev
);
if
(
ret
)
{
ath10k_warn
(
"cannot enable PCI device: %d
\n
"
,
ret
);
return
ret
;
}
pci_read_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
&
val
);
if
((
val
&
0x000000ff
)
!=
0
)
{
pci_restore_state
(
pdev
);
pci_write_config_dword
(
pdev
,
ATH10K_PCI_PM_CONTROL
,
val
&
0xffffff00
);
/*
* Suspend/Resume resets the PCI configuration space,
* so we have to re-disable the RETRY_TIMEOUT register (0x41)
* to keep PCI Tx retries from interfering with C3 CPU state
*/
pci_read_config_dword
(
pdev
,
0x40
,
&
val
);
if
((
val
&
0x0000ff00
)
!=
0
)
pci_write_config_dword
(
pdev
,
0x40
,
val
&
0xffff00ff
);
}
ret
=
ath10k_core_target_resume
(
ar
);
if
(
ret
)
ath10k_warn
(
"target resume failed: %d
\n
"
,
ret
);
return
ret
;
}
static
SIMPLE_DEV_PM_OPS
(
ath10k_dev_pm_ops
,
ath10k_pci_suspend
,
ath10k_pci_resume
);
#define ATH10K_PCI_PM_OPS (&ath10k_dev_pm_ops)
#else
#define ATH10K_PCI_PM_OPS NULL
#endif
/* CONFIG_PM_SLEEP */
MODULE_DEVICE_TABLE
(
pci
,
ath10k_pci_id_table
);
static
struct
pci_driver
ath10k_pci_driver
=
{
...
...
@@ -2474,7 +2429,6 @@ static struct pci_driver ath10k_pci_driver = {
.
id_table
=
ath10k_pci_id_table
,
.
probe
=
ath10k_pci_probe
,
.
remove
=
ath10k_pci_remove
,
.
driver
.
pm
=
ATH10K_PCI_PM_OPS
,
};
static
int
__init
ath10k_pci_init
(
void
)
...
...
drivers/net/wireless/ath/ath10k/pci.h
View file @
1f807827
...
...
@@ -152,7 +152,7 @@ struct service_to_pipe {
enum
ath10k_pci_features
{
ATH10K_PCI_FEATURE_MSI_X
=
0
,
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
=
1
,
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
=
1
,
/* keep last */
ATH10K_PCI_FEATURE_COUNT
...
...
@@ -311,7 +311,7 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
struct
ath10k_pci
*
ar_pci
=
ath10k_pci_priv
(
ar
);
void
__iomem
*
addr
=
ar_pci
->
mem
;
if
(
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
A
RKAROUND
,
ar_pci
->
features
))
{
if
(
test_bit
(
ATH10K_PCI_FEATURE_HW_1_0_W
O
RKAROUND
,
ar_pci
->
features
))
{
unsigned
long
irq_flags
;
spin_lock_irqsave
(
&
ar_pci
->
hw_v1_workaround_lock
,
irq_flags
);
...
...
drivers/net/wireless/ath/ath10k/wmi.c
View file @
1f807827
...
...
@@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar)
{
int
ret
;
lockdep_assert_held
(
&
ar
->
conf_mutex
);
if
(
ar
->
state
==
ATH10K_STATE_WEDGED
)
{
ath10k_warn
(
"wmi flush skipped - device is wedged anyway
\n
"
);
return
;
}
ret
=
wait_event_timeout
(
ar
->
wmi
.
wq
,
atomic_read
(
&
ar
->
wmi
.
pending_tx_count
)
==
0
,
5
*
HZ
);
...
...
@@ -111,7 +118,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
trace_ath10k_wmi_cmd
(
cmd_id
,
skb
->
data
,
skb
->
len
);
status
=
ath10k_htc_send
(
ar
->
htc
,
ar
->
wmi
.
eid
,
skb
);
status
=
ath10k_htc_send
(
&
ar
->
htc
,
ar
->
wmi
.
eid
,
skb
);
if
(
status
)
{
dev_kfree_skb_any
(
skb
);
atomic_dec
(
&
ar
->
wmi
.
pending_tx_count
);
...
...
@@ -501,7 +508,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
ie
=
(
u8
*
)
cfg80211_find_ie
(
WLAN_EID_TIM
,
ies
,
(
u8
*
)
skb_tail_pointer
(
bcn
)
-
ies
);
if
(
!
ie
)
{
/* highly unlikely for mac80211 */
if
(
arvif
->
vdev_type
!=
WMI_VDEV_TYPE_IBSS
)
ath10k_warn
(
"no tim ie found;
\n
"
);
return
;
}
...
...
@@ -1114,7 +1121,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
/* connect to control service */
conn_req
.
service_id
=
ATH10K_HTC_SVC_ID_WMI_CONTROL
;
status
=
ath10k_htc_connect_service
(
ar
->
htc
,
&
conn_req
,
&
conn_resp
);
status
=
ath10k_htc_connect_service
(
&
ar
->
htc
,
&
conn_req
,
&
conn_resp
);
if
(
status
)
{
ath10k_warn
(
"failed to connect to WMI CONTROL service status: %d
\n
"
,
status
);
...
...
@@ -1748,6 +1755,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
if
(
arg
->
key_data
)
memcpy
(
cmd
->
key_data
,
arg
->
key_data
,
arg
->
key_len
);
ath10k_dbg
(
ATH10K_DBG_WMI
,
"wmi vdev install key idx %d cipher %d len %d
\n
"
,
arg
->
key_idx
,
arg
->
key_cipher
,
arg
->
key_len
);
return
ath10k_wmi_cmd_send
(
ar
,
skb
,
WMI_VDEV_INSTALL_KEY_CMDID
);
}
...
...
@@ -2011,6 +2021,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
cmd
->
peer_vht_rates
.
tx_mcs_set
=
__cpu_to_le32
(
arg
->
peer_vht_rates
.
tx_mcs_set
);
ath10k_dbg
(
ATH10K_DBG_WMI
,
"wmi peer assoc vdev %d addr %pM
\n
"
,
arg
->
vdev_id
,
arg
->
addr
);
return
ath10k_wmi_cmd_send
(
ar
,
skb
,
WMI_PEER_ASSOC_CMDID
);
}
...
...
@@ -2079,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
ath10k_dbg
(
ATH10K_DBG_WMI
,
"wmi request stats %d
\n
"
,
(
int
)
stats_id
);
return
ath10k_wmi_cmd_send
(
ar
,
skb
,
WMI_REQUEST_STATS_CMDID
);
}
int
ath10k_wmi_force_fw_hang
(
struct
ath10k
*
ar
,
enum
wmi_force_fw_hang_type
type
,
u32
delay_ms
)
{
struct
wmi_force_fw_hang_cmd
*
cmd
;
struct
sk_buff
*
skb
;
skb
=
ath10k_wmi_alloc_skb
(
sizeof
(
*
cmd
));
if
(
!
skb
)
return
-
ENOMEM
;
cmd
=
(
struct
wmi_force_fw_hang_cmd
*
)
skb
->
data
;
cmd
->
type
=
__cpu_to_le32
(
type
);
cmd
->
delay_ms
=
__cpu_to_le32
(
delay_ms
);
ath10k_dbg
(
ATH10K_DBG_WMI
,
"wmi force fw hang %d delay %d
\n
"
,
type
,
delay_ms
);
return
ath10k_wmi_cmd_send
(
ar
,
skb
,
WMI_FORCE_FW_HANG_CMDID
);
}
drivers/net/wireless/ath/ath10k/wmi.h
View file @
1f807827
...
...
@@ -416,6 +416,7 @@ enum wmi_cmd_id {
WMI_PDEV_FTM_INTG_CMDID
,
WMI_VDEV_SET_KEEPALIVE_CMDID
,
WMI_VDEV_GET_KEEPALIVE_CMDID
,
WMI_FORCE_FW_HANG_CMDID
,
/* GPIO Configuration */
WMI_GPIO_CONFIG_CMDID
=
WMI_CMD_GRP
(
WMI_GRP_GPIO
),
...
...
@@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd {
struct
wmi_sta_keepalive_arp_resp
arp_resp
;
}
__packed
;
enum
wmi_force_fw_hang_type
{
WMI_FORCE_FW_HANG_ASSERT
=
1
,
WMI_FORCE_FW_HANG_NO_DETECT
,
WMI_FORCE_FW_HANG_CTRL_EP_FULL
,
WMI_FORCE_FW_HANG_EMPTY_POINT
,
WMI_FORCE_FW_HANG_STACK_OVERFLOW
,
WMI_FORCE_FW_HANG_INFINITE_LOOP
,
};
#define WMI_FORCE_FW_HANG_RANDOM_TIME 0xFFFFFFFF
struct
wmi_force_fw_hang_cmd
{
__le32
type
;
__le32
delay_ms
;
}
__packed
;
#define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
...
...
@@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg);
int
ath10k_wmi_pdev_set_wmm_params
(
struct
ath10k
*
ar
,
const
struct
wmi_pdev_set_wmm_params_arg
*
arg
);
int
ath10k_wmi_request_stats
(
struct
ath10k
*
ar
,
enum
wmi_stats_id
stats_id
);
int
ath10k_wmi_force_fw_hang
(
struct
ath10k
*
ar
,
enum
wmi_force_fw_hang_type
type
,
u32
delay_ms
);
#endif
/* _WMI_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment