Merge ath-next from ath.git
Major changes: ath9k * add random number generator support (CONFIG_ATH9K_HWRNG)
This commit is contained in:
commit
d0ca990067
@ -1139,7 +1139,7 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[64];
|
||||
u8 amsdu = 3, ampdu = 64;
|
||||
u8 amsdu, ampdu;
|
||||
unsigned int len;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
@ -250,7 +250,8 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP &&
|
||||
arvif->vif->type != NL80211_IFTYPE_ADHOC))
|
||||
arvif->vif->type != NL80211_IFTYPE_ADHOC &&
|
||||
arvif->vif->type != NL80211_IFTYPE_MESH_POINT))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
@ -4312,34 +4312,58 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
|
||||
}
|
||||
|
||||
static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
|
||||
u32 num_units, u32 unit_len)
|
||||
static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id,
|
||||
u32 num_units, u32 unit_len)
|
||||
{
|
||||
dma_addr_t paddr;
|
||||
u32 pool_size;
|
||||
u32 pool_size = 0;
|
||||
int idx = ar->wmi.num_mem_chunks;
|
||||
void *vaddr = NULL;
|
||||
|
||||
pool_size = num_units * round_up(unit_len, 4);
|
||||
if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks))
|
||||
return -ENOMEM;
|
||||
|
||||
if (!pool_size)
|
||||
return -EINVAL;
|
||||
while (!vaddr && num_units) {
|
||||
pool_size = num_units * round_up(unit_len, 4);
|
||||
if (!pool_size)
|
||||
return -EINVAL;
|
||||
|
||||
ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,
|
||||
pool_size,
|
||||
&paddr,
|
||||
GFP_KERNEL);
|
||||
if (!ar->wmi.mem_chunks[idx].vaddr) {
|
||||
ath10k_warn(ar, "failed to allocate memory chunk\n");
|
||||
vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!vaddr)
|
||||
num_units /= 2;
|
||||
}
|
||||
|
||||
if (!num_units)
|
||||
return -ENOMEM;
|
||||
|
||||
paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(ar->dev, paddr)) {
|
||||
kfree(vaddr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size);
|
||||
|
||||
ar->wmi.mem_chunks[idx].vaddr = vaddr;
|
||||
ar->wmi.mem_chunks[idx].paddr = paddr;
|
||||
ar->wmi.mem_chunks[idx].len = pool_size;
|
||||
ar->wmi.mem_chunks[idx].req_id = req_id;
|
||||
ar->wmi.num_mem_chunks++;
|
||||
|
||||
return num_units;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
|
||||
u32 num_units, u32 unit_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (num_units) {
|
||||
ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_units -= ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7717,10 +7741,11 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
|
||||
|
||||
/* free the host memory chunks requested by firmware */
|
||||
for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
|
||||
dma_free_coherent(ar->dev,
|
||||
ar->wmi.mem_chunks[i].len,
|
||||
ar->wmi.mem_chunks[i].vaddr,
|
||||
ar->wmi.mem_chunks[i].paddr);
|
||||
dma_unmap_single(ar->dev,
|
||||
ar->wmi.mem_chunks[i].paddr,
|
||||
ar->wmi.mem_chunks[i].len,
|
||||
DMA_TO_DEVICE);
|
||||
kfree(ar->wmi.mem_chunks[i].vaddr);
|
||||
}
|
||||
|
||||
ar->wmi.num_mem_chunks = 0;
|
||||
|
@ -767,7 +767,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
flags |= AR5K_TXDESC_NOACK;
|
||||
|
||||
rc_flags = info->control.rates[0].flags;
|
||||
rc_flags = bf->rates[0].flags;
|
||||
|
||||
hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0);
|
||||
|
||||
|
@ -3930,8 +3930,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
|
||||
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
|
||||
ar->hw.tx_ant = 2;
|
||||
ar->hw.rx_ant = 2;
|
||||
ar->hw.tx_ant = 0x3; /* mask, 2 antenna */
|
||||
ar->hw.rx_ant = 0x3;
|
||||
} else {
|
||||
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
|
@ -2222,8 +2222,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
|
||||
}
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("failed to get pending recv messages: %d\n",
|
||||
status);
|
||||
if (status != -ECANCELED)
|
||||
ath6kl_err("failed to get pending recv messages: %d\n",
|
||||
status);
|
||||
|
||||
/* cleanup any packets in sync completion queue */
|
||||
list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) {
|
||||
|
@ -954,8 +954,10 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
|
||||
|
||||
ret = request_firmware(&fw, filename, ar->dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath6kl_err("Failed request firmware, rv: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data = fw->data;
|
||||
len = fw->size;
|
||||
@ -964,11 +966,15 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
|
||||
|
||||
if (len < magic_len) {
|
||||
ath6kl_err("Magic length is invalid, len: %zd magic_len: %zd\n",
|
||||
len, magic_len);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
|
||||
ath6kl_err("Magic is invalid, magic_len: %zd\n",
|
||||
magic_len);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -987,7 +993,12 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
len -= sizeof(*hdr);
|
||||
data += sizeof(*hdr);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT, "ie-id: %d len: %zd (0x%zx)\n",
|
||||
ie_id, ie_len, ie_len);
|
||||
|
||||
if (len < ie_len) {
|
||||
ath6kl_err("IE len is invalid, len: %zd ie_len: %zd ie-id: %d\n",
|
||||
len, ie_len, ie_id);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -1008,6 +1019,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
|
||||
|
||||
if (ar->fw_otp == NULL) {
|
||||
ath6kl_err("fw_otp cannot be allocated\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -1025,6 +1037,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
ar->fw = vmalloc(ie_len);
|
||||
|
||||
if (ar->fw == NULL) {
|
||||
ath6kl_err("fw storage cannot be allocated, len: %zd\n", ie_len);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -1039,6 +1052,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
|
||||
ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
|
||||
|
||||
if (ar->fw_patch == NULL) {
|
||||
ath6kl_err("fw_patch storage cannot be allocated, len: %zd\n", ie_len);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -176,3 +176,14 @@ config ATH9K_HTC_DEBUGFS
|
||||
depends on ATH9K_HTC && DEBUG_FS
|
||||
---help---
|
||||
Say Y, if you need access to ath9k_htc's statistics.
|
||||
|
||||
config ATH9K_HWRNG
|
||||
bool "Random number generator support"
|
||||
depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K)
|
||||
default y
|
||||
---help---
|
||||
This option incorporates the ADC register output as a source of
|
||||
randomness into Linux entropy pool (/dev/urandom and /dev/random)
|
||||
|
||||
Say Y, feeds the entropy directly from the WiFi driver to the input
|
||||
pool.
|
||||
|
@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
|
||||
ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
|
||||
ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
|
||||
ath9k-$(CONFIG_ATH9K_WOW) += wow.o
|
||||
ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/hw_random.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
@ -981,6 +982,7 @@ struct ath_softc {
|
||||
struct ath_offchannel offchannel;
|
||||
struct ath_chanctx *next_chan;
|
||||
struct completion go_beacon;
|
||||
struct timespec last_event_time;
|
||||
#endif
|
||||
|
||||
unsigned long driver_data;
|
||||
@ -1040,6 +1042,11 @@ struct ath_softc {
|
||||
u32 wow_intr_before_sleep;
|
||||
bool force_wow;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATH9K_HWRNG
|
||||
u32 rng_last;
|
||||
struct task_struct *rng_task;
|
||||
#endif
|
||||
};
|
||||
|
||||
/********/
|
||||
@ -1062,6 +1069,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc,
|
||||
}
|
||||
#endif /* CONFIG_ATH9K_TX99 */
|
||||
|
||||
/***************************/
|
||||
/* Random Number Generator */
|
||||
/***************************/
|
||||
#ifdef CONFIG_ATH9K_HWRNG
|
||||
void ath9k_rng_start(struct ath_softc *sc);
|
||||
void ath9k_rng_stop(struct ath_softc *sc);
|
||||
#else
|
||||
static inline void ath9k_rng_start(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath9k_rng_stop(struct ath_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
|
||||
{
|
||||
common->bus_ops->read_cachesize(common, csz);
|
||||
|
@ -148,7 +148,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
|
||||
|
||||
ath_assign_seq(common, skb);
|
||||
|
||||
if (vif->p2p)
|
||||
/* Always assign NOA attr when MCC enabled */
|
||||
if (ath9k_is_chanctx_enabled())
|
||||
ath9k_beacon_add_noa(sc, avp, skb);
|
||||
|
||||
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
|
||||
|
@ -226,6 +226,20 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
|
||||
}
|
||||
}
|
||||
|
||||
static const u32 chanctx_event_delta(struct ath_softc *sc)
|
||||
{
|
||||
u64 ms;
|
||||
struct timespec ts, *old;
|
||||
|
||||
getrawmonotonic(&ts);
|
||||
old = &sc->last_event_time;
|
||||
ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
ms -= old->tv_sec * 1000 + old->tv_nsec / 1000000;
|
||||
sc->last_event_time = ts;
|
||||
|
||||
return (u32)ms;
|
||||
}
|
||||
|
||||
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
@ -356,14 +370,16 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
unsigned long timeout;
|
||||
|
||||
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
|
||||
tsf_time -= ath9k_hw_gettsf32(ah);
|
||||
tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
|
||||
mod_timer(&sc->sched.timer, jiffies + tsf_time);
|
||||
timeout = msecs_to_jiffies(tsf_time / 1000) + 1;
|
||||
mod_timer(&sc->sched.timer, jiffies + timeout);
|
||||
|
||||
ath_dbg(common, CHAN_CTX,
|
||||
"Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
|
||||
"Setup chanctx timer with timeout: %d (%d) ms\n",
|
||||
tsf_time / 1000, jiffies_to_msecs(timeout));
|
||||
}
|
||||
|
||||
static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
|
||||
@ -403,7 +419,7 @@ static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
|
||||
avp->offchannel_duration = sc->sched.offchannel_duration;
|
||||
|
||||
ath_dbg(common, CHAN_CTX,
|
||||
"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
|
||||
"offchannel noa_duration: %d, noa_start: %u, noa_index: %d\n",
|
||||
avp->offchannel_duration,
|
||||
avp->offchannel_start,
|
||||
avp->noa_index);
|
||||
@ -443,7 +459,7 @@ static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
|
||||
avp->periodic_noa = true;
|
||||
|
||||
ath_dbg(common, CHAN_CTX,
|
||||
"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
|
||||
"noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
|
||||
avp->noa_duration,
|
||||
avp->noa_start,
|
||||
avp->noa_index,
|
||||
@ -464,7 +480,7 @@ static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
|
||||
avp->noa_duration = duration + sc->sched.channel_switch_time;
|
||||
|
||||
ath_dbg(common, CHAN_CTX,
|
||||
"oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
|
||||
"oneshot noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
|
||||
avp->noa_duration,
|
||||
avp->noa_start,
|
||||
avp->noa_index,
|
||||
@ -487,10 +503,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
|
||||
ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
|
||||
ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s, delta: %u ms\n",
|
||||
sc->cur_chan->chandef.center_freq1,
|
||||
chanctx_event_string(ev),
|
||||
chanctx_state_string(sc->sched.state));
|
||||
chanctx_state_string(sc->sched.state),
|
||||
chanctx_event_delta(sc));
|
||||
|
||||
switch (ev) {
|
||||
case ATH_CHANCTX_EVENT_BEACON_PREPARE:
|
||||
@ -1099,6 +1116,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
|
||||
nullfunc->frame_control |=
|
||||
cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
||||
skb->priority = 7;
|
||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
@ -1401,8 +1419,9 @@ void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
|
||||
|
||||
static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
s32 tsf, target_tsf;
|
||||
u32 tsf, target_tsf;
|
||||
|
||||
if (!avp || !avp->noa.has_next_tsf)
|
||||
return;
|
||||
@ -1414,11 +1433,17 @@ static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
|
||||
target_tsf = avp->noa.next_tsf;
|
||||
if (!avp->noa.absent)
|
||||
target_tsf -= ATH_P2P_PS_STOP_TIME;
|
||||
else
|
||||
target_tsf += ATH_P2P_PS_STOP_TIME;
|
||||
|
||||
if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
|
||||
target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
|
||||
|
||||
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
|
||||
ath_dbg(common, CHAN_CTX, "%s absent %d tsf 0x%08X next_tsf 0x%08X (%dms)\n",
|
||||
__func__, avp->noa.absent, tsf, target_tsf,
|
||||
(target_tsf - tsf) / 1000);
|
||||
|
||||
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, target_tsf, 1000000);
|
||||
}
|
||||
|
||||
static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
@ -1433,6 +1458,10 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
return;
|
||||
|
||||
sc->p2p_ps_vif = avp;
|
||||
|
||||
if (sc->ps_flags & PS_BEACON_SYNC)
|
||||
return;
|
||||
|
||||
tsf = ath9k_hw_gettsf32(sc->sc_ah);
|
||||
ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
|
||||
ath9k_update_p2p_ps_timer(sc, avp);
|
||||
@ -1495,6 +1524,8 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
|
||||
|
||||
noa->index = avp->noa_index;
|
||||
noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
|
||||
if (noa->oppps_ctwindow)
|
||||
noa->oppps_ctwindow |= BIT(7);
|
||||
|
||||
if (avp->noa_duration) {
|
||||
if (avp->periodic_noa) {
|
||||
@ -1536,6 +1567,8 @@ void ath9k_p2p_ps_timer(void *priv)
|
||||
tsf = ath9k_hw_gettsf32(sc->sc_ah);
|
||||
if (!avp->noa.absent)
|
||||
tsf += ATH_P2P_PS_STOP_TIME;
|
||||
else
|
||||
tsf -= ATH_P2P_PS_STOP_TIME;
|
||||
|
||||
if (!avp->noa.has_next_tsf ||
|
||||
avp->noa.next_tsf - tsf > BIT(31))
|
||||
@ -1571,8 +1604,7 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if (!(sc->ps_flags & PS_BEACON_SYNC))
|
||||
ath9k_update_p2p_ps(sc, vif);
|
||||
ath9k_update_p2p_ps(sc, vif);
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
}
|
||||
|
@ -18,30 +18,16 @@
|
||||
|
||||
#define FUDGE 2
|
||||
|
||||
/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
|
||||
static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
|
||||
{
|
||||
u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
|
||||
|
||||
tsf_mod = tsf & (BIT(10) - 1);
|
||||
tsf_hi = tsf >> 32;
|
||||
tsf_lo = ((u32) tsf) >> 10;
|
||||
|
||||
mod_hi = tsf_hi % div_tu;
|
||||
mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
|
||||
|
||||
return (mod_lo << 10) | tsf_mod;
|
||||
}
|
||||
|
||||
static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
|
||||
unsigned int interval)
|
||||
{
|
||||
unsigned int offset;
|
||||
unsigned int offset, divisor;
|
||||
|
||||
tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
|
||||
offset = ath9k_mod_tsf64_tu(tsf, interval);
|
||||
divisor = TU_TO_USEC(interval);
|
||||
div_u64_rem(tsf, divisor, &offset);
|
||||
|
||||
return (u32) tsf + TU_TO_USEC(interval) - offset;
|
||||
return (u32) tsf + divisor - offset;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -138,6 +138,80 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
|
||||
{
|
||||
u16 magic;
|
||||
u16 *eepdata;
|
||||
int i;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
|
||||
ath_err(common, "Reading Magic # failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (magic == AR5416_EEPROM_MAGIC) {
|
||||
*swap_needed = false;
|
||||
} else if (swab16(magic) == AR5416_EEPROM_MAGIC) {
|
||||
if (ah->ah_flags & AH_NO_EEP_SWAP) {
|
||||
ath_info(common,
|
||||
"Ignoring endianness difference in EEPROM magic bytes.\n");
|
||||
|
||||
*swap_needed = false;
|
||||
} else {
|
||||
*swap_needed = true;
|
||||
}
|
||||
} else {
|
||||
ath_err(common,
|
||||
"Invalid EEPROM Magic (0x%04x).\n", magic);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
if (*swap_needed) {
|
||||
ath_dbg(common, EEPROM,
|
||||
"EEPROM Endianness is not native.. Changing.\n");
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
eepdata[i] = swab16(eepdata[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
|
||||
{
|
||||
u32 i, sum = 0;
|
||||
u16 *eepdata = (u16 *)(&ah->eeprom);
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
sum ^= eepdata[i];
|
||||
|
||||
if (sum != 0xffff) {
|
||||
ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (ah->eep_ops->get_eeprom_ver(ah) != version ||
|
||||
ah->eep_ops->get_eeprom_rev(ah) < minrev) {
|
||||
ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
|
||||
ah->eep_ops->get_eeprom_ver(ah),
|
||||
ah->eep_ops->get_eeprom_rev(ah));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
|
||||
u8 *pVpdList, u16 numIntercepts,
|
||||
u8 *pRetVpdList)
|
||||
|
@ -664,6 +664,9 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
|
||||
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
|
||||
u16 *indexL, u16 *indexR);
|
||||
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
|
||||
int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size);
|
||||
bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size);
|
||||
bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev);
|
||||
void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
|
||||
int eep_start_loc, int size);
|
||||
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
|
||||
|
@ -177,74 +177,30 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#undef SIZE_EEPROM_4K
|
||||
|
||||
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
|
||||
u16 *eepdata, temp, magic, magic2;
|
||||
u32 sum = 0, el;
|
||||
bool need_swap = false;
|
||||
int i, addr;
|
||||
u32 el;
|
||||
bool need_swap;
|
||||
int i, err;
|
||||
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
|
||||
&magic)) {
|
||||
ath_err(common, "Reading Magic # failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
|
||||
|
||||
if (magic != AR5416_EEPROM_MAGIC) {
|
||||
magic2 = swab16(magic);
|
||||
|
||||
if (magic2 == AR5416_EEPROM_MAGIC) {
|
||||
need_swap = true;
|
||||
eepdata = (u16 *) (&ah->eeprom);
|
||||
|
||||
for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
|
||||
temp = swab16(*eepdata);
|
||||
*eepdata = temp;
|
||||
eepdata++;
|
||||
}
|
||||
} else {
|
||||
ath_err(common,
|
||||
"Invalid EEPROM Magic. Endianness mismatch.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ath_dbg(common, EEPROM, "need_swap = %s\n",
|
||||
need_swap ? "True" : "False");
|
||||
err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_4K);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (need_swap)
|
||||
el = swab16(ah->eeprom.map4k.baseEepHeader.length);
|
||||
el = swab16(eep->baseEepHeader.length);
|
||||
else
|
||||
el = ah->eeprom.map4k.baseEepHeader.length;
|
||||
el = eep->baseEepHeader.length;
|
||||
|
||||
if (el > sizeof(struct ar5416_eeprom_4k))
|
||||
el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
|
||||
else
|
||||
el = el / sizeof(u16);
|
||||
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
for (i = 0; i < el; i++)
|
||||
sum ^= *eepdata++;
|
||||
el = min(el / sizeof(u16), SIZE_EEPROM_4K);
|
||||
if (!ath9k_hw_nvram_validate_checksum(ah, el))
|
||||
return -EINVAL;
|
||||
|
||||
if (need_swap) {
|
||||
u32 integer;
|
||||
u16 word;
|
||||
|
||||
ath_dbg(common, EEPROM,
|
||||
"EEPROM Endianness is not native.. Changing\n");
|
||||
|
||||
word = swab16(eep->baseEepHeader.length);
|
||||
eep->baseEepHeader.length = word;
|
||||
|
||||
@ -283,17 +239,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
|
||||
}
|
||||
}
|
||||
|
||||
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
|
||||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
|
||||
ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
|
||||
sum, ah->eep_ops->get_eeprom_ver(ah));
|
||||
if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
|
||||
AR5416_EEP_NO_BACK_VER))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#undef EEPROM_4K_SIZE
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_4K
|
||||
|
||||
static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
|
||||
enum eeprom_param param)
|
||||
{
|
||||
|
@ -177,59 +177,24 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
|
||||
static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u32 sum = 0, el, integer;
|
||||
u16 temp, word, magic, magic2, *eepdata;
|
||||
int i, addr;
|
||||
bool need_swap = false;
|
||||
u32 el, integer;
|
||||
u16 word;
|
||||
int i, err;
|
||||
bool need_swap;
|
||||
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!ath9k_hw_use_flash(ah)) {
|
||||
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
|
||||
&magic)) {
|
||||
ath_err(common, "Reading Magic # failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
|
||||
|
||||
if (magic != AR5416_EEPROM_MAGIC) {
|
||||
magic2 = swab16(magic);
|
||||
|
||||
if (magic2 == AR5416_EEPROM_MAGIC) {
|
||||
need_swap = true;
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
|
||||
temp = swab16(*eepdata);
|
||||
*eepdata = temp;
|
||||
eepdata++;
|
||||
}
|
||||
} else {
|
||||
ath_err(common,
|
||||
"Invalid EEPROM Magic. Endianness mismatch.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ath_dbg(common, EEPROM, "need_swap = %s\n",
|
||||
need_swap ? "True" : "False");
|
||||
err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (need_swap)
|
||||
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
|
||||
el = swab16(eep->baseEepHeader.length);
|
||||
else
|
||||
el = ah->eeprom.map9287.baseEepHeader.length;
|
||||
el = eep->baseEepHeader.length;
|
||||
|
||||
if (el > sizeof(struct ar9287_eeprom))
|
||||
el = sizeof(struct ar9287_eeprom) / sizeof(u16);
|
||||
else
|
||||
el = el / sizeof(u16);
|
||||
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
for (i = 0; i < el; i++)
|
||||
sum ^= *eepdata++;
|
||||
el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
|
||||
if (!ath9k_hw_nvram_validate_checksum(ah, el))
|
||||
return -EINVAL;
|
||||
|
||||
if (need_swap) {
|
||||
word = swab16(eep->baseEepHeader.length);
|
||||
@ -270,16 +235,15 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
|
||||
}
|
||||
}
|
||||
|
||||
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
|
||||
|| ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
|
||||
ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
|
||||
sum, ah->eep_ops->get_eeprom_ver(ah));
|
||||
if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
|
||||
AR5416_EEP_NO_BACK_VER))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_AR9287
|
||||
|
||||
static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
|
||||
enum eeprom_param param)
|
||||
{
|
||||
|
@ -126,8 +126,6 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
||||
return __ath9k_hw_def_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_DEF
|
||||
|
||||
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
|
||||
static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
struct modal_eep_header *modal_hdr)
|
||||
@ -257,59 +255,31 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u16 *eepdata, temp, magic;
|
||||
u32 sum = 0, el;
|
||||
bool need_swap = false;
|
||||
int i, addr, size;
|
||||
u32 el;
|
||||
bool need_swap;
|
||||
int i, err;
|
||||
|
||||
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
|
||||
ath_err(common, "Reading Magic # failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (swab16(magic) == AR5416_EEPROM_MAGIC &&
|
||||
!(ah->ah_flags & AH_NO_EEP_SWAP)) {
|
||||
size = sizeof(struct ar5416_eeprom_def);
|
||||
need_swap = true;
|
||||
eepdata = (u16 *) (&ah->eeprom);
|
||||
|
||||
for (addr = 0; addr < size / sizeof(u16); addr++) {
|
||||
temp = swab16(*eepdata);
|
||||
*eepdata = temp;
|
||||
eepdata++;
|
||||
}
|
||||
}
|
||||
|
||||
ath_dbg(common, EEPROM, "need_swap = %s\n",
|
||||
need_swap ? "True" : "False");
|
||||
err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_DEF);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (need_swap)
|
||||
el = swab16(ah->eeprom.def.baseEepHeader.length);
|
||||
el = swab16(eep->baseEepHeader.length);
|
||||
else
|
||||
el = ah->eeprom.def.baseEepHeader.length;
|
||||
el = eep->baseEepHeader.length;
|
||||
|
||||
if (el > sizeof(struct ar5416_eeprom_def))
|
||||
el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
|
||||
else
|
||||
el = el / sizeof(u16);
|
||||
|
||||
eepdata = (u16 *)(&ah->eeprom);
|
||||
|
||||
for (i = 0; i < el; i++)
|
||||
sum ^= *eepdata++;
|
||||
el = min(el / sizeof(u16), SIZE_EEPROM_DEF);
|
||||
if (!ath9k_hw_nvram_validate_checksum(ah, el))
|
||||
return -EINVAL;
|
||||
|
||||
if (need_swap) {
|
||||
u32 integer, j;
|
||||
u16 word;
|
||||
|
||||
ath_dbg(common, EEPROM,
|
||||
"EEPROM Endianness is not native.. Changing.\n");
|
||||
|
||||
word = swab16(eep->baseEepHeader.length);
|
||||
eep->baseEepHeader.length = word;
|
||||
|
||||
@ -356,12 +326,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
}
|
||||
}
|
||||
|
||||
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
|
||||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
|
||||
ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
|
||||
sum, ah->eep_ops->get_eeprom_ver(ah));
|
||||
if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
|
||||
AR5416_EEP_NO_BACK_VER))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable fixup for AR_AN_TOP2 if necessary */
|
||||
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
|
||||
@ -376,6 +343,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef SIZE_EEPROM_DEF
|
||||
|
||||
static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
|
||||
enum eeprom_param param)
|
||||
{
|
||||
|
@ -2299,10 +2299,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
|
||||
else
|
||||
nextTbtt = bs->bs_nexttbtt;
|
||||
|
||||
ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim);
|
||||
ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt);
|
||||
ath_dbg(common, BEACON, "beacon period %d\n", beaconintval);
|
||||
ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod);
|
||||
ath_dbg(common, BEACON, "next DTIM %u\n", bs->bs_nextdtim);
|
||||
ath_dbg(common, BEACON, "next beacon %u\n", nextTbtt);
|
||||
ath_dbg(common, BEACON, "beacon period %u\n", beaconintval);
|
||||
ath_dbg(common, BEACON, "DTIM period %u\n", dtimperiod);
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
@ -2761,9 +2761,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
|
||||
bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
|
||||
|
||||
REG_WRITE(ah, AR_RX_FILTER, bits);
|
||||
|
||||
phybits = 0;
|
||||
|
@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
ath9k_rng_start(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
|
||||
ath9k_deinit_channel_context(sc);
|
||||
|
||||
ath9k_rng_stop(sc);
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
ath_cancel_work(sc);
|
||||
|
@ -424,6 +424,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
AR_SREV_9561(sc->sc_ah))
|
||||
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
|
||||
|
||||
if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
|
||||
rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
|
||||
|
||||
if (ath9k_is_chanctx_enabled() &&
|
||||
test_bit(ATH_OP_SCANNING, &common->op_flags))
|
||||
rfilt |= ATH9K_RX_FILTER_BEACON;
|
||||
|
107
drivers/net/wireless/ath/ath9k/rng.c
Normal file
107
drivers/net/wireless/ath/ath9k/rng.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "ath9k.h"
|
||||
#include "hw.h"
|
||||
#include "ar9003_phy.h"
|
||||
|
||||
#define ATH9K_RNG_BUF_SIZE 320
|
||||
#define ATH9K_RNG_ENTROPY(x) (((x) * 8 * 320) >> 10) /* quality: 320/1024 */
|
||||
|
||||
static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
|
||||
{
|
||||
int i, j;
|
||||
u32 v1, v2, rng_last = sc->rng_last;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
|
||||
REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
|
||||
REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
|
||||
|
||||
for (i = 0, j = 0; i < buf_size; i++) {
|
||||
v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
|
||||
v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
|
||||
|
||||
/* wait for data ready */
|
||||
if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff &&
|
||||
v2 != 0xffff)
|
||||
buf[j++] = (v1 << 16) | v2;
|
||||
|
||||
rng_last = v2;
|
||||
}
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->rng_last = rng_last;
|
||||
|
||||
return j << 2;
|
||||
}
|
||||
|
||||
static int ath9k_rng_kthread(void *data)
|
||||
{
|
||||
int bytes_read;
|
||||
struct ath_softc *sc = data;
|
||||
u32 *rng_buf;
|
||||
|
||||
rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL);
|
||||
if (!rng_buf)
|
||||
goto out;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
bytes_read = ath9k_rng_data_read(sc, rng_buf,
|
||||
ATH9K_RNG_BUF_SIZE);
|
||||
if (unlikely(!bytes_read)) {
|
||||
msleep_interruptible(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* sleep until entropy bits under write_wakeup_threshold */
|
||||
add_hwgenerator_randomness((void *)rng_buf, bytes_read,
|
||||
ATH9K_RNG_ENTROPY(bytes_read));
|
||||
}
|
||||
|
||||
kfree(rng_buf);
|
||||
out:
|
||||
sc->rng_task = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath9k_rng_start(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (sc->rng_task)
|
||||
return;
|
||||
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
return;
|
||||
|
||||
sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng");
|
||||
if (IS_ERR(sc->rng_task))
|
||||
sc->rng_task = NULL;
|
||||
}
|
||||
|
||||
void ath9k_rng_stop(struct ath_softc *sc)
|
||||
{
|
||||
if (sc->rng_task)
|
||||
kthread_stop(sc->rng_task);
|
||||
}
|
@ -1473,11 +1473,14 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_tid *txtid;
|
||||
struct ath_txq *txq;
|
||||
struct ath_node *an;
|
||||
u8 density;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
txtid = ATH_AN_2_TID(an, tid);
|
||||
txq = txtid->txq;
|
||||
@ -1512,10 +1515,13 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
|
||||
struct ath_txq *txq = txtid->txq;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
txtid->active = false;
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
@ -1526,11 +1532,14 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
|
||||
struct ath_node *an)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_txq *txq;
|
||||
bool buffered;
|
||||
int tidno;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
|
||||
@ -1555,10 +1564,13 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
|
||||
|
||||
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_txq *txq;
|
||||
int tidno;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
|
||||
@ -1579,10 +1591,13 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
|
||||
u16 tidno)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_node *an;
|
||||
struct ath_txq *txq;
|
||||
|
||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
tid = ATH_AN_2_TID(an, tidno);
|
||||
txq = tid->txq;
|
||||
@ -2316,6 +2331,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
|
||||
queue = ieee80211_is_data_present(hdr->frame_control);
|
||||
|
||||
/* If chanctx, queue all null frames while NOA could be there */
|
||||
if (ath9k_is_chanctx_enabled() &&
|
||||
ieee80211_is_nullfunc(hdr->frame_control) &&
|
||||
!txctl->force_channel)
|
||||
queue = true;
|
||||
|
||||
/* Force queueing of all frames that belong to a virtual interface on
|
||||
* a different channel context, to ensure that they are sent on the
|
||||
* correct channel.
|
||||
@ -2894,7 +2915,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
|
||||
if (skb_headroom(skb) < padsize) {
|
||||
ath_dbg(common, XMIT,
|
||||
"tx99 padding failed\n");
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb_push(skb, padsize);
|
||||
|
@ -781,8 +781,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
|
||||
/* prevent NAPI from being scheduled */
|
||||
/* prevent NAPI from being scheduled and prevent wmi commands */
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
bitmap_zero(wil->status, wil_status_last);
|
||||
mutex_unlock(&wil->wmi_mutex);
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
|
||||
|
@ -228,6 +228,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
|
||||
/* wait till FW finish with previous command */
|
||||
for (retry = 5; retry > 0; retry--) {
|
||||
if (!test_bit(wil_status_fwready, wil->status)) {
|
||||
wil_err(wil, "WMI: cannot send command while FW not ready\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
r->tail = wil_r(wil, RGF_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx.tail));
|
||||
if (next_head != r->tail)
|
||||
|
Loading…
Reference in New Issue
Block a user