Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
7916a07557
|
@ -1865,7 +1865,6 @@ static int adm8211_probe(struct pci_dev *pdev,
|
|||
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
dev->channel_change_time = 1000;
|
||||
dev->max_signal = 100; /* FIXME: find better value */
|
||||
|
||||
dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
|
||||
|
|
|
@ -2112,7 +2112,6 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
|
|||
priv->pm_period = 0;
|
||||
|
||||
/* unit us */
|
||||
priv->hw->channel_change_time = 100000;
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef ATH_H
|
||||
#define ATH_H
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -165,6 +166,7 @@ struct ath_common {
|
|||
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
u32 len,
|
||||
gfp_t gfp_mask);
|
||||
bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);
|
||||
|
||||
void ath_hw_setbssidmask(struct ath_common *common);
|
||||
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
|
||||
|
|
|
@ -37,3 +37,10 @@ config ATH10K_TRACING
|
|||
---help---
|
||||
Select this to ath10k use tracing infrastructure.
|
||||
|
||||
config ATH10K_DFS_CERTIFIED
|
||||
bool "Atheros DFS support for certified platforms"
|
||||
depends on ATH10K && CFG80211_CERTIFICATION_ONUS
|
||||
default n
|
||||
---help---
|
||||
This option enables DFS support for initiating radiation on
|
||||
ath10k.
|
||||
|
|
|
@ -253,6 +253,9 @@ struct ath10k_vif {
|
|||
u8 bssid[ETH_ALEN];
|
||||
} ibss;
|
||||
} u;
|
||||
|
||||
u8 fixed_rate;
|
||||
u8 fixed_nss;
|
||||
};
|
||||
|
||||
struct ath10k_vif_iter {
|
||||
|
@ -272,6 +275,8 @@ struct ath10k_debug {
|
|||
struct delayed_work htt_stats_dwork;
|
||||
struct ath10k_dfs_stats dfs_stats;
|
||||
struct ath_dfs_pool_stats dfs_pool_stats;
|
||||
|
||||
u32 fw_dbglog_mask;
|
||||
};
|
||||
|
||||
enum ath10k_state {
|
||||
|
@ -306,6 +311,9 @@ enum ath10k_fw_features {
|
|||
/* firmware support tx frame management over WMI, otherwise it's HTT */
|
||||
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2,
|
||||
|
||||
/* Firmware does not support P2P */
|
||||
ATH10K_FW_FEATURE_NO_P2P = 3,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
|
@ -429,6 +437,9 @@ struct ath10k {
|
|||
struct list_head peers;
|
||||
wait_queue_head_t peer_mapping_wq;
|
||||
|
||||
/* number of created peers; protected by data_lock */
|
||||
int num_peers;
|
||||
|
||||
struct work_struct offchan_tx_work;
|
||||
struct sk_buff_head offchan_tx_queue;
|
||||
struct completion offchan_tx_completed;
|
||||
|
|
|
@ -614,6 +614,61 @@ static const struct file_operations fops_htt_stats_mask = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_read_fw_dbglog(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned int len;
|
||||
char buf[32];
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "0x%08x\n",
|
||||
ar->debug.fw_dbglog_mask);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_write_fw_dbglog(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned long mask;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul_from_user(user_buf, count, 0, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ar->debug.fw_dbglog_mask = mask;
|
||||
|
||||
if (ar->state == ATH10K_STATE_ON) {
|
||||
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
|
||||
if (ret) {
|
||||
ath10k_warn("dbglog cfg failed from debugfs: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_fw_dbglog = {
|
||||
.read = ath10k_read_fw_dbglog,
|
||||
.write = ath10k_write_fw_dbglog,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_start(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
@ -625,6 +680,14 @@ int ath10k_debug_start(struct ath10k *ar)
|
|||
/* continue normally anyway, this isn't serious */
|
||||
ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
|
||||
|
||||
if (ar->debug.fw_dbglog_mask) {
|
||||
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
|
||||
if (ret)
|
||||
/* not serious */
|
||||
ath10k_warn("failed to enable dbglog during start: %d",
|
||||
ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -747,6 +810,9 @@ int ath10k_debug_create(struct ath10k *ar)
|
|||
debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_htt_stats_mask);
|
||||
|
||||
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_fw_dbglog);
|
||||
|
||||
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
|
||||
debugfs_create_file("dfs_simulate_radar", S_IWUSR,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
|
|
|
@ -1183,6 +1183,7 @@ struct htt_rx_info {
|
|||
} rate;
|
||||
bool fcs_err;
|
||||
bool amsdu_more;
|
||||
bool mic_err;
|
||||
};
|
||||
|
||||
struct ath10k_htt {
|
||||
|
|
|
@ -838,6 +838,20 @@ static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
|
@ -960,6 +974,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
|
||||
info.skb = msdu_head;
|
||||
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
|
||||
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
|
||||
info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
info.signal += rx->ppdu.combined_rssi;
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ enum ath10k_mcast2ucast_mode {
|
|||
#define TARGET_10X_MAC_AGGR_DELIM 0
|
||||
#define TARGET_10X_AST_SKID_LIMIT 16
|
||||
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
|
||||
#define TARGET_10X_NUM_PEERS_MAX 128
|
||||
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
|
||||
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
|
||||
#define TARGET_10X_NUM_PEER_KEYS 2
|
||||
|
|
|
@ -332,6 +332,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
|||
ath10k_warn("Failed to wait for created wmi peer: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->num_peers++;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -377,6 +380,10 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->num_peers--;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -396,6 +403,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
|
|||
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
@ -411,6 +419,7 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
|
|||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
}
|
||||
ar->num_peers = 0;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
|
@ -2205,7 +2214,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
enum wmi_sta_powersave_param param;
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
u32 value, param_id;
|
||||
int bit;
|
||||
u32 vdev_param;
|
||||
|
||||
|
@ -2297,6 +2306,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|||
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
param_id = ar->wmi.pdev_param->sta_kickout_th;
|
||||
|
||||
/* Disable STA KICKOUT functionality in FW */
|
||||
ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to disable STA KICKOUT\n");
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
|
||||
|
@ -2842,6 +2858,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
int max_num_peers;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
@ -2852,9 +2869,21 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
/*
|
||||
* New station addition.
|
||||
*/
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
|
||||
max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
|
||||
else
|
||||
max_num_peers = TARGET_NUM_PEERS;
|
||||
|
||||
if (ar->num_peers >= max_num_peers) {
|
||||
ath10k_warn("Number of peers exceeded: peers number %d (max peers %d)\n",
|
||||
ar->num_peers, max_num_peers);
|
||||
ret = -ENOBUFS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d peer create %pM (new sta)\n",
|
||||
arvif->vdev_id, sta->addr);
|
||||
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
|
||||
arvif->vdev_id, sta->addr, ar->num_peers);
|
||||
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret)
|
||||
|
@ -2904,7 +2933,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
ath10k_warn("Failed to disassociate station: %pM\n",
|
||||
sta->addr);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -3310,6 +3339,307 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Helper table for legacy fixed_rate/bitrate_mask */
|
||||
static const u8 cck_ofdm_rate[] = {
|
||||
/* CCK */
|
||||
3, /* 1Mbps */
|
||||
2, /* 2Mbps */
|
||||
1, /* 5.5Mbps */
|
||||
0, /* 11Mbps */
|
||||
/* OFDM */
|
||||
3, /* 6Mbps */
|
||||
7, /* 9Mbps */
|
||||
2, /* 12Mbps */
|
||||
6, /* 18Mbps */
|
||||
1, /* 24Mbps */
|
||||
5, /* 36Mbps */
|
||||
0, /* 48Mbps */
|
||||
4, /* 54Mbps */
|
||||
};
|
||||
|
||||
/* Check if only one bit set */
|
||||
static int ath10k_check_single_mask(u32 mask)
|
||||
{
|
||||
int bit;
|
||||
|
||||
bit = ffs(mask);
|
||||
if (!bit)
|
||||
return 0;
|
||||
|
||||
mask &= ~BIT(bit - 1);
|
||||
if (mask)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_default_bitrate_mask(struct ath10k *ar,
|
||||
enum ieee80211_band band,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
u32 legacy = 0x00ff;
|
||||
u8 ht = 0xff, i;
|
||||
u16 vht = 0x3ff;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
legacy = 0x00fff;
|
||||
vht = 0;
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mask->control[band].legacy != legacy)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ar->num_rf_chains; i++)
|
||||
if (mask->control[band].ht_mcs[i] != ht)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ar->num_rf_chains; i++)
|
||||
if (mask->control[band].vht_mcs[i] != vht)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
int ht_nss = 0, vht_nss = 0, i;
|
||||
|
||||
/* check legacy */
|
||||
if (ath10k_check_single_mask(mask->control[band].legacy))
|
||||
return false;
|
||||
|
||||
/* check HT */
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
|
||||
if (mask->control[band].ht_mcs[i] == 0xff)
|
||||
continue;
|
||||
else if (mask->control[band].ht_mcs[i] == 0x00)
|
||||
break;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
ht_nss = i;
|
||||
|
||||
/* check VHT */
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
|
||||
if (mask->control[band].vht_mcs[i] == 0x03ff)
|
||||
continue;
|
||||
else if (mask->control[band].vht_mcs[i] == 0x0000)
|
||||
break;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
vht_nss = i;
|
||||
|
||||
if (ht_nss > 0 && vht_nss > 0)
|
||||
return false;
|
||||
|
||||
if (ht_nss)
|
||||
*fixed_nss = ht_nss;
|
||||
else if (vht_nss)
|
||||
*fixed_nss = vht_nss;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
enum wmi_rate_preamble *preamble)
|
||||
{
|
||||
int legacy = 0, ht = 0, vht = 0, i;
|
||||
|
||||
*preamble = WMI_RATE_PREAMBLE_OFDM;
|
||||
|
||||
/* check legacy */
|
||||
legacy = ath10k_check_single_mask(mask->control[band].legacy);
|
||||
if (legacy > 1)
|
||||
return false;
|
||||
|
||||
/* check HT */
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
ht += ath10k_check_single_mask(mask->control[band].ht_mcs[i]);
|
||||
if (ht > 1)
|
||||
return false;
|
||||
|
||||
/* check VHT */
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
|
||||
vht += ath10k_check_single_mask(mask->control[band].vht_mcs[i]);
|
||||
if (vht > 1)
|
||||
return false;
|
||||
|
||||
/* Currently we support only one fixed_rate */
|
||||
if ((legacy + ht + vht) != 1)
|
||||
return false;
|
||||
|
||||
if (ht)
|
||||
*preamble = WMI_RATE_PREAMBLE_HT;
|
||||
else if (vht)
|
||||
*preamble = WMI_RATE_PREAMBLE_VHT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_rate,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
u8 rate = 0, pream = 0, nss = 0, i;
|
||||
enum wmi_rate_preamble preamble;
|
||||
|
||||
/* Check if single rate correct */
|
||||
if (!ath10k_bitrate_mask_correct(mask, band, &preamble))
|
||||
return false;
|
||||
|
||||
pream = preamble;
|
||||
|
||||
switch (preamble) {
|
||||
case WMI_RATE_PREAMBLE_CCK:
|
||||
case WMI_RATE_PREAMBLE_OFDM:
|
||||
i = ffs(mask->control[band].legacy) - 1;
|
||||
|
||||
if (band == IEEE80211_BAND_2GHZ && i < 4)
|
||||
pream = WMI_RATE_PREAMBLE_CCK;
|
||||
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
i += 4;
|
||||
|
||||
if (i >= ARRAY_SIZE(cck_ofdm_rate))
|
||||
return false;
|
||||
|
||||
rate = cck_ofdm_rate[i];
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_HT:
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
if (mask->control[band].ht_mcs[i])
|
||||
break;
|
||||
|
||||
if (i == IEEE80211_HT_MCS_MASK_LEN)
|
||||
return false;
|
||||
|
||||
rate = ffs(mask->control[band].ht_mcs[i]) - 1;
|
||||
nss = i;
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_VHT:
|
||||
for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
|
||||
if (mask->control[band].vht_mcs[i])
|
||||
break;
|
||||
|
||||
if (i == NL80211_VHT_NSS_MAX)
|
||||
return false;
|
||||
|
||||
rate = ffs(mask->control[band].vht_mcs[i]) - 1;
|
||||
nss = i;
|
||||
break;
|
||||
}
|
||||
|
||||
*fixed_nss = nss + 1;
|
||||
nss <<= 4;
|
||||
pream <<= 6;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
|
||||
pream, nss, rate);
|
||||
|
||||
*fixed_rate = pream | nss | rate;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
|
||||
enum ieee80211_band band,
|
||||
u8 *fixed_rate,
|
||||
u8 *fixed_nss)
|
||||
{
|
||||
/* First check full NSS mask, if we can simply limit NSS */
|
||||
if (ath10k_bitrate_mask_nss(mask, band, fixed_nss))
|
||||
return true;
|
||||
|
||||
/* Next Check single rate is set */
|
||||
return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
|
||||
}
|
||||
|
||||
static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
|
||||
u8 fixed_rate,
|
||||
u8 fixed_nss)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 vdev_param;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (arvif->fixed_rate == fixed_rate &&
|
||||
arvif->fixed_nss == fixed_nss)
|
||||
goto exit;
|
||||
|
||||
if (fixed_rate == WMI_FIXED_RATE_NONE)
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->fixed_rate;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
vdev_param, fixed_rate);
|
||||
if (ret) {
|
||||
ath10k_warn("Could not set fixed_rate param 0x%02x: %d\n",
|
||||
fixed_rate, ret);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arvif->fixed_rate = fixed_rate;
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->nss;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
vdev_param, fixed_nss);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn("Could not set fixed_nss param %d: %d\n",
|
||||
fixed_nss, ret);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arvif->fixed_nss = fixed_nss;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k *ar = arvif->ar;
|
||||
enum ieee80211_band band = ar->hw->conf.chandef.chan->band;
|
||||
u8 fixed_rate = WMI_FIXED_RATE_NONE;
|
||||
u8 fixed_nss = ar->num_rf_chains;
|
||||
|
||||
if (!ath10k_default_bitrate_mask(ar, band, mask)) {
|
||||
if (!ath10k_get_fixed_rate_nss(mask, band,
|
||||
&fixed_rate,
|
||||
&fixed_nss))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx = ath10k_tx,
|
||||
.start = ath10k_start,
|
||||
|
@ -3332,6 +3662,7 @@ static const struct ieee80211_ops ath10k_ops = {
|
|||
.tx_last_beacon = ath10k_tx_last_beacon,
|
||||
.restart_complete = ath10k_restart_complete,
|
||||
.get_survey = ath10k_get_survey,
|
||||
.set_bitrate_mask = ath10k_set_bitrate_mask,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ath10k_suspend,
|
||||
.resume = ath10k_resume,
|
||||
|
@ -3464,14 +3795,12 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
static const struct ieee80211_iface_limit ath10k_if_dfs_limits[] = {
|
||||
static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
|
||||
{
|
||||
.max = 8,
|
||||
.types = BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
|
||||
{
|
||||
|
@ -3481,19 +3810,22 @@ static const struct ieee80211_iface_combination ath10k_if_comb[] = {
|
|||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
},
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
|
||||
{
|
||||
.limits = ath10k_if_dfs_limits,
|
||||
.n_limits = ARRAY_SIZE(ath10k_if_dfs_limits),
|
||||
.limits = ath10k_10x_if_limits,
|
||||
.n_limits = ARRAY_SIZE(ath10k_10x_if_limits),
|
||||
.max_interfaces = 8,
|
||||
.num_different_channels = 1,
|
||||
.beacon_int_infra_match = true,
|
||||
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
|
||||
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||
BIT(NL80211_CHAN_WIDTH_20) |
|
||||
BIT(NL80211_CHAN_WIDTH_40) |
|
||||
BIT(NL80211_CHAN_WIDTH_80),
|
||||
}
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
||||
|
@ -3672,9 +4004,12 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
ar->hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
|
||||
ar->hw->wiphy->interface_modes |=
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
|
@ -3704,7 +4039,6 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
|
||||
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
||||
|
||||
ar->hw->channel_change_time = 5000;
|
||||
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
|
||||
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
|
@ -3717,8 +4051,15 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
*/
|
||||
ar->hw->queues = 4;
|
||||
|
||||
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb);
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
|
||||
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(ath10k_10x_if_comb);
|
||||
} else {
|
||||
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
|
||||
ar->hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(ath10k_if_comb);
|
||||
}
|
||||
|
||||
ar->hw->netdev_features = NETIF_F_HW_CSUM;
|
||||
|
||||
|
|
|
@ -182,6 +182,27 @@ TRACE_EVENT(ath10k_htt_stats,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_dbglog,
|
||||
TP_PROTO(void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"len %zu",
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
|
||||
|
||||
/* we don't want to use include/trace/events */
|
||||
|
|
|
@ -231,7 +231,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
|||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
if (info->status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR)
|
||||
if (info->mic_err)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (info->fcs_err)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "htc.h"
|
||||
|
@ -875,6 +876,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
struct wmi_mgmt_rx_event_v2 *ev_v2;
|
||||
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_channel *ch;
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 rx_status;
|
||||
u32 channel;
|
||||
|
@ -927,7 +929,25 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
if (rx_status & WMI_RX_STATUS_ERR_MIC)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
status->band = phy_mode_to_band(phy_mode);
|
||||
/* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to
|
||||
* MODE_11B. This means phy_mode is not a reliable source for the band
|
||||
* of mgmt rx. */
|
||||
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
|
||||
if (ch) {
|
||||
status->band = ch->band;
|
||||
|
||||
if (phy_mode == MODE_11B &&
|
||||
status->band == IEEE80211_BAND_5GHZ)
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
|
||||
} else {
|
||||
ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
|
||||
status->band = phy_mode_to_band(phy_mode);
|
||||
}
|
||||
|
||||
status->freq = ieee80211_channel_to_frequency(channel, status->band);
|
||||
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
status->rate_idx = get_rate_idx(rate, status->band);
|
||||
|
@ -937,7 +957,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
if (fc & IEEE80211_FCTL_PROTECTED) {
|
||||
/* FW delivers WEP Shared Auth frame with Protected Bit set and
|
||||
* encrypted payload. However in case of PMF it delivers decrypted
|
||||
* frames with Protected Bit set. */
|
||||
if (ieee80211_has_protected(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
|
@ -1047,9 +1071,14 @@ static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
|
|||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
|
||||
static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_MESG_EVENTID\n");
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
|
||||
skb->len);
|
||||
|
||||
trace_ath10k_wmi_dbglog(skb->data, skb->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_update_stats(struct ath10k *ar,
|
||||
|
@ -1653,9 +1682,37 @@ static void ath10k_wmi_event_profile_match(struct ath10k *ar,
|
|||
}
|
||||
|
||||
static void ath10k_wmi_event_debug_print(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_DEBUG_PRINT_EVENTID\n");
|
||||
char buf[101], c;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(buf) - 1; i++) {
|
||||
if (i >= skb->len)
|
||||
break;
|
||||
|
||||
c = skb->data[i];
|
||||
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
if (isascii(c) && isprint(c))
|
||||
buf[i] = c;
|
||||
else
|
||||
buf[i] = '.';
|
||||
}
|
||||
|
||||
if (i == sizeof(buf) - 1)
|
||||
ath10k_warn("wmi debug print truncated: %d\n", skb->len);
|
||||
|
||||
/* for some reason the debug prints end with \n, remove that */
|
||||
if (skb->data[i - 1] == '\n')
|
||||
i--;
|
||||
|
||||
/* the last byte is always reserved for the null character */
|
||||
buf[i] = '\0';
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
|
||||
}
|
||||
|
||||
static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
|
||||
|
@ -3445,3 +3502,40 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
|
|||
type, delay_ms);
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
|
||||
}
|
||||
|
||||
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
|
||||
{
|
||||
struct wmi_dbglog_cfg_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
u32 cfg;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
|
||||
|
||||
if (module_enable) {
|
||||
cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE,
|
||||
ATH10K_DBGLOG_CFG_LOG_LVL);
|
||||
} else {
|
||||
/* set back defaults, all modules with WARN level */
|
||||
cfg = SM(ATH10K_DBGLOG_LEVEL_WARN,
|
||||
ATH10K_DBGLOG_CFG_LOG_LVL);
|
||||
module_enable = ~0;
|
||||
}
|
||||
|
||||
cmd->module_enable = __cpu_to_le32(module_enable);
|
||||
cmd->module_valid = __cpu_to_le32(~0);
|
||||
cmd->config_enable = __cpu_to_le32(cfg);
|
||||
cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI,
|
||||
"wmi dbglog cfg modules %08x %08x config %08x %08x\n",
|
||||
__le32_to_cpu(cmd->module_enable),
|
||||
__le32_to_cpu(cmd->module_valid),
|
||||
__le32_to_cpu(cmd->config_enable),
|
||||
__le32_to_cpu(cmd->config_valid));
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
|
||||
}
|
||||
|
|
|
@ -3003,6 +3003,18 @@ struct wmi_vdev_install_key_arg {
|
|||
const void *key_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* vdev fixed rate format:
|
||||
* - preamble - b7:b6 - see WMI_RATE_PREMABLE_
|
||||
* - nss - b5:b4 - ss number (0 mean 1ss)
|
||||
* - rate_mcs - b3:b0 - as below
|
||||
* CCK: 0 - 11Mbps, 1 - 5,5Mbps, 2 - 2Mbps, 3 - 1Mbps,
|
||||
* 4 - 11Mbps (s), 5 - 5,5Mbps (s), 6 - 2Mbps (s)
|
||||
* OFDM: 0 - 48Mbps, 1 - 24Mbps, 2 - 12Mbps, 3 - 6Mbps,
|
||||
* 4 - 54Mbps, 5 - 36Mbps, 6 - 18Mbps, 7 - 9Mbps
|
||||
* HT/VHT: MCS index
|
||||
*/
|
||||
|
||||
/* Preamble types to be used with VDEV fixed rate configuration */
|
||||
enum wmi_rate_preamble {
|
||||
WMI_RATE_PREAMBLE_OFDM,
|
||||
|
@ -4090,6 +4102,54 @@ struct wmi_force_fw_hang_cmd {
|
|||
__le32 delay_ms;
|
||||
} __packed;
|
||||
|
||||
enum ath10k_dbglog_level {
|
||||
ATH10K_DBGLOG_LEVEL_VERBOSE = 0,
|
||||
ATH10K_DBGLOG_LEVEL_INFO = 1,
|
||||
ATH10K_DBGLOG_LEVEL_WARN = 2,
|
||||
ATH10K_DBGLOG_LEVEL_ERR = 3,
|
||||
};
|
||||
|
||||
/* VAP ids to enable dbglog */
|
||||
#define ATH10K_DBGLOG_CFG_VAP_LOG_LSB 0
|
||||
#define ATH10K_DBGLOG_CFG_VAP_LOG_MASK 0x0000ffff
|
||||
|
||||
/* to enable dbglog in the firmware */
|
||||
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_LSB 16
|
||||
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_MASK 0x00010000
|
||||
|
||||
/* timestamp resolution */
|
||||
#define ATH10K_DBGLOG_CFG_RESOLUTION_LSB 17
|
||||
#define ATH10K_DBGLOG_CFG_RESOLUTION_MASK 0x000E0000
|
||||
|
||||
/* number of queued messages before sending them to the host */
|
||||
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_LSB 20
|
||||
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_MASK 0x0ff00000
|
||||
|
||||
/*
|
||||
* Log levels to enable. This defines the minimum level to enable, this is
|
||||
* not a bitmask. See enum ath10k_dbglog_level for the values.
|
||||
*/
|
||||
#define ATH10K_DBGLOG_CFG_LOG_LVL_LSB 28
|
||||
#define ATH10K_DBGLOG_CFG_LOG_LVL_MASK 0x70000000
|
||||
|
||||
/*
|
||||
* Note: this is a cleaned up version of a struct firmware uses. For
|
||||
* example, config_valid was hidden inside an array.
|
||||
*/
|
||||
struct wmi_dbglog_cfg_cmd {
|
||||
/* bitmask to hold mod id config*/
|
||||
__le32 module_enable;
|
||||
|
||||
/* see ATH10K_DBGLOG_CFG_ */
|
||||
__le32 config_enable;
|
||||
|
||||
/* mask of module id bits to be changed */
|
||||
__le32 module_valid;
|
||||
|
||||
/* mask of config bits to be changed, see ATH10K_DBGLOG_CFG_ */
|
||||
__le32 config_valid;
|
||||
} __packed;
|
||||
|
||||
#define ATH10K_RTS_MAX 2347
|
||||
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
|
||||
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
|
||||
|
@ -4167,5 +4227,6 @@ 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);
|
||||
int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
|
||||
|
||||
#endif /* _WMI_H_ */
|
||||
|
|
|
@ -1238,14 +1238,11 @@ static void
|
|||
ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rxs)
|
||||
{
|
||||
struct ath_common *common = ath5k_hw_common(ah);
|
||||
u64 tsf, bc_tstamp;
|
||||
u32 hw_tu;
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
|
||||
if (ieee80211_is_beacon(mgmt->frame_control) &&
|
||||
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
|
||||
ether_addr_equal_64bits(mgmt->bssid, common->curbssid)) {
|
||||
if (le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS) {
|
||||
/*
|
||||
* Received an IBSS beacon with the same BSSID. Hardware *must*
|
||||
* have updated the local TSF. We have to work around various
|
||||
|
@ -1301,23 +1298,6 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
struct ath_common *common = ath5k_hw_common(ah);
|
||||
|
||||
/* only beacons from our BSSID */
|
||||
if (!ieee80211_is_beacon(mgmt->frame_control) ||
|
||||
!ether_addr_equal_64bits(mgmt->bssid, common->curbssid))
|
||||
return;
|
||||
|
||||
ewma_add(&ah->ah_beacon_rssi_avg, rssi);
|
||||
|
||||
/* in IBSS mode we should keep RSSI statistics per neighbour */
|
||||
/* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute padding position. skb must contain an IEEE 802.11 frame
|
||||
*/
|
||||
|
@ -1390,6 +1370,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
|
|||
struct ath5k_rx_status *rs)
|
||||
{
|
||||
struct ieee80211_rx_status *rxs;
|
||||
struct ath_common *common = ath5k_hw_common(ah);
|
||||
|
||||
ath5k_remove_padding(skb);
|
||||
|
||||
|
@ -1442,11 +1423,13 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
|
|||
|
||||
trace_ath5k_rx(ah, skb);
|
||||
|
||||
ath5k_update_beacon_rssi(ah, skb, rs->rs_rssi);
|
||||
if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) {
|
||||
ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi);
|
||||
|
||||
/* check beacons in IBSS mode */
|
||||
if (ah->opmode == NL80211_IFTYPE_ADHOC)
|
||||
ath5k_check_ibss_tsf(ah, skb, rxs);
|
||||
/* check beacons in IBSS mode */
|
||||
if (ah->opmode == NL80211_IFTYPE_ADHOC)
|
||||
ath5k_check_ibss_tsf(ah, skb, rxs);
|
||||
}
|
||||
|
||||
ieee80211_rx(ah->hw, skb);
|
||||
}
|
||||
|
@ -2549,7 +2532,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
|||
hw->wiphy->available_antennas_rx = 0x3;
|
||||
|
||||
hw->extra_tx_headroom = 2;
|
||||
hw->channel_change_time = 5000;
|
||||
|
||||
/*
|
||||
* Mark the device as detached to avoid processing
|
||||
|
|
|
@ -65,6 +65,14 @@ config ATH9K_DEBUGFS
|
|||
|
||||
Also required for changing debug message flags at run time.
|
||||
|
||||
config ATH9K_STATION_STATISTICS
|
||||
bool "Detailed station statistics"
|
||||
depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS
|
||||
select MAC80211_DEBUGFS
|
||||
default n
|
||||
---help---
|
||||
This option enables detailed statistics for association stations.
|
||||
|
||||
config ATH9K_DFS_CERTIFIED
|
||||
bool "Atheros DFS support for certified platforms"
|
||||
depends on ATH9K && CFG80211_CERTIFICATION_ONUS
|
||||
|
|
|
@ -19,6 +19,8 @@ ath9k-$(CONFIG_ATH9K_WOW) += wow.o
|
|||
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \
|
||||
spectral.o
|
||||
|
||||
ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o
|
||||
|
||||
obj-$(CONFIG_ATH9K) += ath9k.o
|
||||
|
||||
ath9k_hw-y:= \
|
||||
|
|
|
@ -565,7 +565,7 @@ static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
|
|||
const s32 result_shift = 1 << 15;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
f2 = (f1 * f1 + f3 * f3) / result_shift;
|
||||
f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9;
|
||||
|
||||
if (!f2) {
|
||||
ath_dbg(common, CALIBRATE, "Divide by 0\n");
|
||||
|
@ -655,8 +655,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
|
|||
if (i2_m_q2_a0_d1 > 0x800)
|
||||
i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
|
||||
|
||||
if (i2_p_q2_a0_d1 > 0x800)
|
||||
i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
|
||||
if (i2_p_q2_a0_d1 > 0x1000)
|
||||
i2_p_q2_a0_d1 = -((0x1fff - i2_p_q2_a0_d1) + 1);
|
||||
|
||||
if (iq_corr_a0_d1 > 0x800)
|
||||
iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
|
||||
|
@ -700,6 +700,19 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) ||
|
||||
(i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
|
||||
(i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
|
||||
(i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
|
||||
(i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
|
||||
(i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
|
||||
(i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
|
||||
(i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
|
||||
(i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
|
||||
(i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
|
||||
phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
|
||||
|
||||
|
|
|
@ -146,7 +146,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
|
||||
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
|
||||
|
||||
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
|
||||
#define IS_HT_RATE(rate) (rate & 0x80)
|
||||
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
|
||||
#define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf))
|
||||
|
||||
struct ath_txq {
|
||||
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
|
||||
|
@ -262,6 +264,10 @@ struct ath_node {
|
|||
|
||||
bool sleeping;
|
||||
bool no_ps_filter;
|
||||
|
||||
#ifdef CONFIG_ATH9K_STATION_STATISTICS
|
||||
struct ath_rx_rate_stats rx_rate_stats;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ath_tx_control {
|
||||
|
@ -685,6 +691,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
|
|||
#define DEFAULT_CACHELINE 32
|
||||
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
|
||||
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
|
||||
#define MAX_GTT_CNT 5
|
||||
|
||||
enum sc_op_flags {
|
||||
SC_OP_INVALID,
|
||||
|
@ -727,6 +734,7 @@ struct ath_softc {
|
|||
unsigned long sc_flags;
|
||||
unsigned long driver_data;
|
||||
|
||||
u8 gtt_cnt;
|
||||
u32 intrstatus;
|
||||
u16 ps_flags; /* PS_* */
|
||||
u16 curtxpow;
|
||||
|
|
|
@ -943,14 +943,10 @@ static const struct file_operations fops_reset = {
|
|||
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
#define PHY_ERR(s, p) \
|
||||
len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.phy_err_stats[p]);
|
||||
|
||||
#define RXS_ERR(s, e) \
|
||||
do { \
|
||||
len += scnprintf(buf + len, size - len, \
|
||||
"%22s : %10u\n", s, \
|
||||
"%18s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.e);\
|
||||
} while (0)
|
||||
|
||||
|
@ -963,6 +959,12 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
|||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
RXS_ERR("PKTS-ALL", rx_pkts_all);
|
||||
RXS_ERR("BYTES-ALL", rx_bytes_all);
|
||||
RXS_ERR("BEACONS", rx_beacons);
|
||||
RXS_ERR("FRAGS", rx_frags);
|
||||
RXS_ERR("SPECTRAL", rx_spectral);
|
||||
|
||||
RXS_ERR("CRC ERR", crc_err);
|
||||
RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err);
|
||||
RXS_ERR("PHY ERR", phy_err);
|
||||
|
@ -970,43 +972,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
|||
RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err);
|
||||
RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err);
|
||||
RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err);
|
||||
RXS_ERR("RX-LENGTH-ERR", rx_len_err);
|
||||
RXS_ERR("RX-OOM-ERR", rx_oom_err);
|
||||
RXS_ERR("RX-RATE-ERR", rx_rate_err);
|
||||
RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
|
||||
|
||||
PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
|
||||
PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
|
||||
PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY);
|
||||
PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE);
|
||||
PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH);
|
||||
PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR);
|
||||
PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE);
|
||||
PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR);
|
||||
PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING);
|
||||
PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
|
||||
PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
|
||||
PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
|
||||
PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP);
|
||||
PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE);
|
||||
PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART);
|
||||
PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
|
||||
PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING);
|
||||
PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC);
|
||||
PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
|
||||
PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
|
||||
PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
|
||||
PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
|
||||
PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP);
|
||||
PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR);
|
||||
PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
|
||||
PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
|
||||
|
||||
RXS_ERR("RX-Pkts-All", rx_pkts_all);
|
||||
RXS_ERR("RX-Bytes-All", rx_bytes_all);
|
||||
RXS_ERR("RX-Beacons", rx_beacons);
|
||||
RXS_ERR("RX-Frags", rx_frags);
|
||||
RXS_ERR("RX-Spectral", rx_spectral);
|
||||
RXS_ERR("LENGTH-ERR", rx_len_err);
|
||||
RXS_ERR("OOM-ERR", rx_oom_err);
|
||||
RXS_ERR("RATE-ERR", rx_rate_err);
|
||||
RXS_ERR("TOO-MANY-FRAGS", rx_too_many_frags_err);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
@ -1017,7 +986,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
|
|||
return retval;
|
||||
|
||||
#undef RXS_ERR
|
||||
#undef PHY_ERR
|
||||
}
|
||||
|
||||
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
|
||||
|
@ -1056,6 +1024,67 @@ static const struct file_operations fops_recv = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_phy_err(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
#define PHY_ERR(s, p) \
|
||||
len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \
|
||||
sc->debug.stats.rxstats.phy_err_stats[p]);
|
||||
|
||||
struct ath_softc *sc = file->private_data;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 1600;
|
||||
ssize_t retval = 0;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
|
||||
PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING);
|
||||
PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY);
|
||||
PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE);
|
||||
PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH);
|
||||
PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR);
|
||||
PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE);
|
||||
PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR);
|
||||
PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING);
|
||||
PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
|
||||
PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
|
||||
PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
|
||||
PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP);
|
||||
PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE);
|
||||
PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART);
|
||||
PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
|
||||
PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING);
|
||||
PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC);
|
||||
PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
|
||||
PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
|
||||
PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
|
||||
PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
|
||||
PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP);
|
||||
PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR);
|
||||
PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
|
||||
PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
|
||||
#undef PHY_ERR
|
||||
}
|
||||
|
||||
static const struct file_operations fops_phy_err = {
|
||||
.read = read_file_phy_err,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -1322,86 +1351,6 @@ static const struct file_operations fops_btcoex = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static ssize_t read_file_node_stat(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_node *an = file->private_data;
|
||||
struct ath_softc *sc = an->sc;
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_txq *txq;
|
||||
u32 len = 0, size = 4096;
|
||||
char *buf;
|
||||
size_t retval;
|
||||
int tidno, acno;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!an->sta->ht_cap.ht_supported) {
|
||||
len = scnprintf(buf, size, "%s\n",
|
||||
"HT not supported");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = scnprintf(buf, size, "Max-AMPDU: %d\n",
|
||||
an->maxampdu);
|
||||
len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n",
|
||||
an->mpdudensity);
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%2s%7s\n", "AC", "SCHED");
|
||||
|
||||
for (acno = 0, ac = &an->ac[acno];
|
||||
acno < IEEE80211_NUM_ACS; acno++, ac++) {
|
||||
txq = ac->txq;
|
||||
ath_txq_lock(sc, txq);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%2d%7d\n",
|
||||
acno, ac->sched);
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",
|
||||
"TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
|
||||
"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
txq = tid->ac->txq;
|
||||
ath_txq_lock(sc, txq);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%3d%11d%10d%10d%10d%10d%9d%6d%8d\n",
|
||||
tid->tidno, tid->seq_start, tid->seq_next,
|
||||
tid->baw_size, tid->baw_head, tid->baw_tail,
|
||||
tid->bar_index, tid->sched, tid->paused);
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
exit:
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_node_stat = {
|
||||
.read = read_file_node_stat,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct dentry *dir)
|
||||
{
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
debugfs_create_file("node_stat", S_IRUGO, dir, an, &fops_node_stat);
|
||||
}
|
||||
|
||||
/* Ethtool support for get-stats */
|
||||
|
||||
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
|
||||
|
@ -1569,6 +1518,8 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
&fops_reset);
|
||||
debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_recv);
|
||||
debugfs_create_file("phy_err", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_phy_err);
|
||||
debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy,
|
||||
&ah->rxchainmask);
|
||||
debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy,
|
||||
|
|
|
@ -27,11 +27,13 @@ struct fft_sample_tlv;
|
|||
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
|
||||
#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
|
||||
#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
|
||||
#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++
|
||||
#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;
|
||||
#else
|
||||
#define TX_STAT_INC(q, c) do { } while (0)
|
||||
#define RX_STAT_INC(c)
|
||||
#define RESET_STAT_INC(sc, type) do { } while (0)
|
||||
#define ANT_STAT_INC(i, c) do { } while (0)
|
||||
#define ANT_LNA_INC(i, c) do { } while (0)
|
||||
|
@ -42,6 +44,7 @@ enum ath_reset_type {
|
|||
RESET_TYPE_BB_WATCHDOG,
|
||||
RESET_TYPE_FATAL_INT,
|
||||
RESET_TYPE_TX_ERROR,
|
||||
RESET_TYPE_TX_GTT,
|
||||
RESET_TYPE_TX_HANG,
|
||||
RESET_TYPE_PLL_HANG,
|
||||
RESET_TYPE_MAC_HANG,
|
||||
|
@ -201,7 +204,23 @@ struct ath_tx_stats {
|
|||
TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
|
||||
} while(0)
|
||||
|
||||
#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
|
||||
struct ath_rx_rate_stats {
|
||||
struct {
|
||||
u32 ht20_cnt;
|
||||
u32 ht40_cnt;
|
||||
u32 sgi_cnt;
|
||||
u32 lgi_cnt;
|
||||
} ht_stats[24];
|
||||
|
||||
struct {
|
||||
u32 ofdm_cnt;
|
||||
} ofdm_stats[8];
|
||||
|
||||
struct {
|
||||
u32 cck_lp_cnt;
|
||||
u32 cck_sp_cnt;
|
||||
} cck_stats[4];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ath_rx_stats - RX Statistics
|
||||
|
@ -299,8 +318,6 @@ void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause);
|
|||
|
||||
#else
|
||||
|
||||
#define RX_STAT_INC(c) /* NOP */
|
||||
|
||||
static inline int ath9k_init_debug(struct ath_hw *ah)
|
||||
{
|
||||
return 0;
|
||||
|
@ -338,4 +355,16 @@ ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause)
|
|||
|
||||
#endif /* CONFIG_ATH9K_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH9K_STATION_STATISTICS
|
||||
void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
struct ath_rx_status *rs,
|
||||
struct sk_buff *skb);
|
||||
#else
|
||||
static inline void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
struct ath_rx_status *rs,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH9K_STATION_STATISTICS */
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright (c) 2013 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 "ath9k.h"
|
||||
|
||||
/*************/
|
||||
/* node_aggr */
|
||||
/*************/
|
||||
|
||||
static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_node *an = file->private_data;
|
||||
struct ath_softc *sc = an->sc;
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_atx_ac *ac;
|
||||
struct ath_txq *txq;
|
||||
u32 len = 0, size = 4096;
|
||||
char *buf;
|
||||
size_t retval;
|
||||
int tidno, acno;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!an->sta->ht_cap.ht_supported) {
|
||||
len = scnprintf(buf, size, "%s\n",
|
||||
"HT not supported");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = scnprintf(buf, size, "Max-AMPDU: %d\n",
|
||||
an->maxampdu);
|
||||
len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n",
|
||||
an->mpdudensity);
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%2s%7s\n", "AC", "SCHED");
|
||||
|
||||
for (acno = 0, ac = &an->ac[acno];
|
||||
acno < IEEE80211_NUM_ACS; acno++, ac++) {
|
||||
txq = ac->txq;
|
||||
ath_txq_lock(sc, txq);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%2d%7d\n",
|
||||
acno, ac->sched);
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",
|
||||
"TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
|
||||
"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
txq = tid->ac->txq;
|
||||
ath_txq_lock(sc, txq);
|
||||
if (tid->active) {
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%3d%11d%10d%10d%10d%10d%9d%6d%8d\n",
|
||||
tid->tidno,
|
||||
tid->seq_start,
|
||||
tid->seq_next,
|
||||
tid->baw_size,
|
||||
tid->baw_head,
|
||||
tid->baw_tail,
|
||||
tid->bar_index,
|
||||
tid->sched,
|
||||
tid->paused);
|
||||
}
|
||||
ath_txq_unlock(sc, txq);
|
||||
}
|
||||
exit:
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_node_aggr = {
|
||||
.read = read_file_node_aggr,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
/*************/
|
||||
/* node_recv */
|
||||
/*************/
|
||||
|
||||
void ath_debug_rate_stats(struct ath_softc *sc,
|
||||
struct ath_rx_status *rs,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_rx_status *rxs;
|
||||
struct ath_rx_rate_stats *rstats;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath_node *an;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(sc->hw, hdr->addr2, NULL);
|
||||
if (!sta)
|
||||
goto exit;
|
||||
|
||||
an = (struct ath_node *) sta->drv_priv;
|
||||
rstats = &an->rx_rate_stats;
|
||||
rxs = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
if (IS_HT_RATE(rs->rs_rate)) {
|
||||
if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats))
|
||||
goto exit;
|
||||
|
||||
if (rxs->flag & RX_FLAG_40MHZ)
|
||||
rstats->ht_stats[rxs->rate_idx].ht40_cnt++;
|
||||
else
|
||||
rstats->ht_stats[rxs->rate_idx].ht20_cnt++;
|
||||
|
||||
if (rxs->flag & RX_FLAG_SHORT_GI)
|
||||
rstats->ht_stats[rxs->rate_idx].sgi_cnt++;
|
||||
else
|
||||
rstats->ht_stats[rxs->rate_idx].lgi_cnt++;
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (IS_CCK_RATE(rs->rs_rate)) {
|
||||
if (rxs->flag & RX_FLAG_SHORTPRE)
|
||||
rstats->cck_stats[rxs->rate_idx].cck_sp_cnt++;
|
||||
else
|
||||
rstats->cck_stats[rxs->rate_idx].cck_lp_cnt++;
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (IS_OFDM_RATE(rs->rs_rate)) {
|
||||
if (ah->curchan->chan->band == IEEE80211_BAND_2GHZ)
|
||||
rstats->ofdm_stats[rxs->rate_idx - 4].ofdm_cnt++;
|
||||
else
|
||||
rstats->ofdm_stats[rxs->rate_idx].ofdm_cnt++;
|
||||
}
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
#define PRINT_CCK_RATE(str, i, sp) \
|
||||
do { \
|
||||
len += scnprintf(buf + len, size - len, \
|
||||
"%11s : %10u\n", \
|
||||
str, \
|
||||
(sp) ? rstats->cck_stats[i].cck_sp_cnt : \
|
||||
rstats->cck_stats[i].cck_lp_cnt); \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_OFDM_RATE(str, i) \
|
||||
do { \
|
||||
len += scnprintf(buf + len, size - len, \
|
||||
"%11s : %10u\n", \
|
||||
str, \
|
||||
rstats->ofdm_stats[i].ofdm_cnt); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t read_file_node_recv(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_node *an = file->private_data;
|
||||
struct ath_softc *sc = an->sc;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_rx_rate_stats *rstats;
|
||||
struct ieee80211_sta *sta = an->sta;
|
||||
enum ieee80211_band band;
|
||||
u32 len = 0, size = 4096;
|
||||
char *buf;
|
||||
size_t retval;
|
||||
int i;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
band = ah->curchan->chan->band;
|
||||
rstats = &an->rx_rate_stats;
|
||||
|
||||
if (!sta->ht_cap.ht_supported)
|
||||
goto legacy;
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%24s%10s%10s%10s\n",
|
||||
"HT20", "HT40", "SGI", "LGI");
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"%8s%3u : %10u%10u%10u%10u\n",
|
||||
"MCS", i,
|
||||
rstats->ht_stats[i].ht20_cnt,
|
||||
rstats->ht_stats[i].ht40_cnt,
|
||||
rstats->ht_stats[i].sgi_cnt,
|
||||
rstats->ht_stats[i].lgi_cnt);
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
|
||||
legacy:
|
||||
if (band == IEEE80211_BAND_2GHZ) {
|
||||
PRINT_CCK_RATE("CCK-1M/LP", 0, false);
|
||||
PRINT_CCK_RATE("CCK-2M/LP", 1, false);
|
||||
PRINT_CCK_RATE("CCK-5.5M/LP", 2, false);
|
||||
PRINT_CCK_RATE("CCK-11M/LP", 3, false);
|
||||
|
||||
PRINT_CCK_RATE("CCK-2M/SP", 1, true);
|
||||
PRINT_CCK_RATE("CCK-5.5M/SP", 2, true);
|
||||
PRINT_CCK_RATE("CCK-11M/SP", 3, true);
|
||||
}
|
||||
|
||||
PRINT_OFDM_RATE("OFDM-6M", 0);
|
||||
PRINT_OFDM_RATE("OFDM-9M", 1);
|
||||
PRINT_OFDM_RATE("OFDM-12M", 2);
|
||||
PRINT_OFDM_RATE("OFDM-18M", 3);
|
||||
PRINT_OFDM_RATE("OFDM-24M", 4);
|
||||
PRINT_OFDM_RATE("OFDM-36M", 5);
|
||||
PRINT_OFDM_RATE("OFDM-48M", 6);
|
||||
PRINT_OFDM_RATE("OFDM-54M", 7);
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#undef PRINT_OFDM_RATE
|
||||
#undef PRINT_CCK_RATE
|
||||
|
||||
static const struct file_operations fops_node_recv = {
|
||||
.read = read_file_node_recv,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct dentry *dir)
|
||||
{
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr);
|
||||
debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv);
|
||||
}
|
|
@ -748,7 +748,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
|||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
hw->max_listen_interval = 1;
|
||||
|
||||
hw->vif_data_size = sizeof(struct ath9k_htc_vif);
|
||||
|
|
|
@ -1075,9 +1075,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
|
|||
|
||||
last_rssi = priv->rx.last_rssi;
|
||||
|
||||
if (ieee80211_is_beacon(hdr->frame_control) &&
|
||||
!is_zero_ether_addr(common->curbssid) &&
|
||||
ether_addr_equal_64bits(hdr->addr3, common->curbssid)) {
|
||||
if (ath_is_mybeacon(common, hdr)) {
|
||||
s8 rssi = rxbuf->rxstatus.rs_rssi;
|
||||
|
||||
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
|
||||
|
|
|
@ -946,7 +946,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
hw->max_listen_interval = 1;
|
||||
hw->max_rate_tries = 10;
|
||||
hw->sta_data_size = sizeof(struct ath_node);
|
||||
|
|
|
@ -258,6 +258,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
|
|||
}
|
||||
}
|
||||
|
||||
sc->gtt_cnt = 0;
|
||||
ieee80211_wake_queues(sc->hw);
|
||||
|
||||
return true;
|
||||
|
@ -476,6 +477,19 @@ void ath9k_tasklet(unsigned long data)
|
|||
}
|
||||
}
|
||||
|
||||
if (status & ATH9K_INT_GTT) {
|
||||
sc->gtt_cnt++;
|
||||
|
||||
if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
|
||||
type = RESET_TYPE_TX_GTT;
|
||||
ath9k_queue_reset(sc, type);
|
||||
atomic_inc(&ah->intr_ref_cnt);
|
||||
ath_dbg(common, ANY,
|
||||
"GTT: Skipping interrupts\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
|
||||
/*
|
||||
|
@ -503,10 +517,19 @@ void ath9k_tasklet(unsigned long data)
|
|||
}
|
||||
|
||||
if (status & ATH9K_INT_TX) {
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
||||
/*
|
||||
* For EDMA chips, TX completion is enabled for the
|
||||
* beacon queue, so if a beacon has been transmitted
|
||||
* successfully after a GTT interrupt, the GTT counter
|
||||
* gets reset to zero here.
|
||||
*/
|
||||
/* sc->gtt_cnt = 0; */
|
||||
|
||||
ath_tx_edma_tasklet(sc);
|
||||
else
|
||||
} else {
|
||||
ath_tx_tasklet(sc);
|
||||
}
|
||||
|
||||
wake_up(&sc->tx_wait);
|
||||
}
|
||||
|
@ -536,13 +559,13 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||
ATH9K_INT_TX | \
|
||||
ATH9K_INT_BMISS | \
|
||||
ATH9K_INT_CST | \
|
||||
ATH9K_INT_GTT | \
|
||||
ATH9K_INT_TSFOOR | \
|
||||
ATH9K_INT_GENTIMER | \
|
||||
ATH9K_INT_MCI)
|
||||
|
||||
struct ath_softc *sc = dev;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
enum ath9k_int status;
|
||||
u32 sync_cause = 0;
|
||||
bool sched = false;
|
||||
|
@ -603,14 +626,12 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||
#ifdef CONFIG_ATH9K_WOW
|
||||
if (status & ATH9K_INT_BMISS) {
|
||||
if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
|
||||
ath_dbg(common, ANY, "during WoW we got a BMISS\n");
|
||||
atomic_inc(&sc->wow_got_bmiss_intr);
|
||||
atomic_dec(&sc->wow_sleep_proc_intr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (status & ATH9K_INT_SWBA)
|
||||
tasklet_schedule(&sc->bcon_tasklet);
|
||||
|
||||
|
@ -735,7 +756,12 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
|||
if (ah->config.hw_hang_checks & HW_BB_WATCHDOG)
|
||||
ah->imask |= ATH9K_INT_BB_WATCHDOG;
|
||||
|
||||
ah->imask |= ATH9K_INT_GTT;
|
||||
/*
|
||||
* Enable GTT interrupts only for AR9003/AR9004 chips
|
||||
* for now.
|
||||
*/
|
||||
if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
ah->imask |= ATH9K_INT_GTT;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
|
||||
ah->imask |= ATH9K_INT_CST;
|
||||
|
@ -2111,7 +2137,7 @@ struct ieee80211_ops ath9k_ops = {
|
|||
.get_et_strings = ath9k_get_et_strings,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
|
||||
#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS)
|
||||
.sta_add_debugfs = ath9k_sta_add_debugfs,
|
||||
#endif
|
||||
.sw_scan_start = ath9k_sw_scan_start,
|
||||
|
|
|
@ -969,21 +969,6 @@ static void ath9k_process_tsf(struct ath_rx_status *rs,
|
|||
rxs->mactime += 0x100000000ULL;
|
||||
}
|
||||
|
||||
static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
RX_STAT_INC(rx_beacons);
|
||||
if (!is_zero_ether_addr(common->curbssid) &&
|
||||
ether_addr_equal_64bits(hdr->addr3, common->curbssid))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* For Decrypt or Demic errors, we only mark packet status here and always push
|
||||
* up the frame up to let mac80211 handle the actual error case, be it no
|
||||
|
@ -1071,7 +1056,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
|
||||
if (ath_is_mybeacon(common, hdr)) {
|
||||
RX_STAT_INC(rx_beacons);
|
||||
rx_stats->is_mybeacon = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This shouldn't happen, but have a safety check anyway.
|
||||
|
@ -1354,8 +1342,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
|
||||
ath9k_antenna_check(sc, &rs);
|
||||
|
||||
ath9k_apply_ampdu_details(sc, &rs, rxs);
|
||||
ath_debug_rate_stats(sc, &rs, skb);
|
||||
|
||||
ieee80211_rx(hw, skb);
|
||||
|
||||
|
|
|
@ -47,8 +47,6 @@ static u16 bits_per_symbol[][2] = {
|
|||
{ 260, 540 }, /* 7: 64-QAM 5/6 */
|
||||
};
|
||||
|
||||
#define IS_HT_RATE(_rate) ((_rate) & 0x80)
|
||||
|
||||
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid, struct sk_buff *skb);
|
||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
|
|
|
@ -1967,18 +1967,6 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
|
|||
return -ENOMEM;
|
||||
ar->num_channels = chans;
|
||||
|
||||
/*
|
||||
* I measured this, a bandswitch takes roughly
|
||||
* 135 ms and a frequency switch about 80.
|
||||
*
|
||||
* FIXME: measure these values again once EEPROM settings
|
||||
* are used, that will influence them!
|
||||
*/
|
||||
if (bands == 2)
|
||||
ar->hw->channel_change_time = 135 * 1000;
|
||||
else
|
||||
ar->hw->channel_change_time = 80 * 1000;
|
||||
|
||||
regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
|
||||
|
||||
/* second part of wiphy init */
|
||||
|
|
|
@ -519,6 +519,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
|
|||
{
|
||||
struct ieee80211_hdr *hdr = data;
|
||||
struct ieee80211_tim_ie *tim_ie;
|
||||
struct ath_common *common = &ar->common;
|
||||
u8 *tim;
|
||||
u8 tim_len;
|
||||
bool cam;
|
||||
|
@ -526,17 +527,13 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
|
|||
if (likely(!(ar->hw->conf.flags & IEEE80211_CONF_PS)))
|
||||
return;
|
||||
|
||||
/* check if this really is a beacon */
|
||||
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||
return;
|
||||
|
||||
/* min. beacon length + FCS_LEN */
|
||||
if (len <= 40 + FCS_LEN)
|
||||
return;
|
||||
|
||||
/* check if this really is a beacon */
|
||||
/* and only beacons from the associated BSSID, please */
|
||||
if (!ether_addr_equal_64bits(hdr->addr3, ar->common.curbssid) ||
|
||||
!ar->common.curaid)
|
||||
if (!ath_is_mybeacon(common, hdr) || !common->curaid)
|
||||
return;
|
||||
|
||||
ar->ps.last_beacon = jiffies;
|
||||
|
|
|
@ -59,6 +59,14 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
|||
}
|
||||
EXPORT_SYMBOL(ath_rxbuf_alloc);
|
||||
|
||||
bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr)
|
||||
{
|
||||
return ieee80211_is_beacon(hdr->frame_control) &&
|
||||
!is_zero_ether_addr(common->curbssid) &&
|
||||
ether_addr_equal_64bits(hdr->addr3, common->curbssid);
|
||||
}
|
||||
EXPORT_SYMBOL(ath_is_mybeacon);
|
||||
|
||||
void ath_printk(const char *level, const struct ath_common* common,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
|
|
|
@ -632,7 +632,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
|||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
wiphy->reg_notifier = reg_notifier;
|
||||
wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
||||
wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
|
||||
REGULATORY_CUSTOM_REG;
|
||||
|
||||
if (ath_is_world_regd(reg)) {
|
||||
/*
|
||||
|
@ -640,8 +641,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
|||
* saved on the wiphy orig_* parameters
|
||||
*/
|
||||
regd = ath_world_regdomain(reg);
|
||||
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
|
||||
REGULATORY_COUNTRY_IE_FOLLOW_POWER;
|
||||
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER;
|
||||
} else {
|
||||
/*
|
||||
* This gets applied in the case of the absence of CRDA,
|
||||
|
@ -650,6 +650,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
|||
*/
|
||||
regd = ath_default_world_regdomain();
|
||||
}
|
||||
|
||||
wiphy_apply_custom_regulatory(wiphy, regd);
|
||||
ath_reg_apply_radar_flags(wiphy);
|
||||
ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <asm/processor.h>
|
||||
#include <linux/prefetch.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
|
|
@ -731,8 +731,6 @@ enum b43_firmware_file_type {
|
|||
struct b43_request_fw_context {
|
||||
/* The device we are requesting the fw for. */
|
||||
struct b43_wldev *dev;
|
||||
/* a completion event structure needed if this call is asynchronous */
|
||||
struct completion fw_load_complete;
|
||||
/* a pointer to the firmware object */
|
||||
const struct firmware *blob;
|
||||
/* The type of firmware to request. */
|
||||
|
@ -809,6 +807,8 @@ enum {
|
|||
struct b43_wldev {
|
||||
struct b43_bus_dev *dev;
|
||||
struct b43_wl *wl;
|
||||
/* a completion event structure needed if this call is asynchronous */
|
||||
struct completion fw_load_complete;
|
||||
|
||||
/* The device initialization status.
|
||||
* Use b43_status() to query. */
|
||||
|
|
|
@ -2070,6 +2070,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw)
|
|||
|
||||
static void b43_release_firmware(struct b43_wldev *dev)
|
||||
{
|
||||
complete(&dev->fw_load_complete);
|
||||
b43_do_release_fw(&dev->fw.ucode);
|
||||
b43_do_release_fw(&dev->fw.pcm);
|
||||
b43_do_release_fw(&dev->fw.initvals);
|
||||
|
@ -2095,7 +2096,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context)
|
|||
struct b43_request_fw_context *ctx = context;
|
||||
|
||||
ctx->blob = firmware;
|
||||
complete(&ctx->fw_load_complete);
|
||||
complete(&ctx->dev->fw_load_complete);
|
||||
}
|
||||
|
||||
int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||||
|
@ -2142,7 +2143,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
}
|
||||
if (async) {
|
||||
/* do this part asynchronously */
|
||||
init_completion(&ctx->fw_load_complete);
|
||||
init_completion(&ctx->dev->fw_load_complete);
|
||||
err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
|
||||
ctx->dev->dev->dev, GFP_KERNEL,
|
||||
ctx, b43_fw_cb);
|
||||
|
@ -2150,12 +2151,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
pr_err("Unable to load firmware\n");
|
||||
return err;
|
||||
}
|
||||
/* stall here until fw ready */
|
||||
wait_for_completion(&ctx->fw_load_complete);
|
||||
wait_for_completion(&ctx->dev->fw_load_complete);
|
||||
if (ctx->blob)
|
||||
goto fw_ready;
|
||||
/* On some ARM systems, the async request will fail, but the next sync
|
||||
* request works. For this reason, we dall through here
|
||||
* request works. For this reason, we fall through here
|
||||
*/
|
||||
}
|
||||
err = request_firmware(&ctx->blob, ctx->fwname,
|
||||
|
@ -2424,6 +2424,7 @@ error:
|
|||
|
||||
static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl);
|
||||
static void b43_one_core_detach(struct b43_bus_dev *dev);
|
||||
static int b43_rng_init(struct b43_wl *wl);
|
||||
|
||||
static void b43_request_firmware(struct work_struct *work)
|
||||
{
|
||||
|
@ -2475,6 +2476,10 @@ start_ieee80211:
|
|||
goto err_one_core_detach;
|
||||
wl->hw_registred = true;
|
||||
b43_leds_register(wl->current_dev);
|
||||
|
||||
/* Register HW RNG driver */
|
||||
b43_rng_init(wl);
|
||||
|
||||
goto out;
|
||||
|
||||
err_one_core_detach:
|
||||
|
@ -4636,9 +4641,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
|||
if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
|
||||
return;
|
||||
|
||||
/* Unregister HW RNG driver */
|
||||
b43_rng_exit(dev->wl);
|
||||
|
||||
b43_set_status(dev, B43_STAT_UNINIT);
|
||||
|
||||
/* Stop the microcode PSM. */
|
||||
|
@ -4795,9 +4797,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
|||
|
||||
b43_set_status(dev, B43_STAT_INITIALIZED);
|
||||
|
||||
/* Register HW RNG driver */
|
||||
b43_rng_init(dev->wl);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
|
@ -5464,6 +5463,9 @@ static void b43_bcma_remove(struct bcma_device *core)
|
|||
|
||||
b43_one_core_detach(wldev->dev);
|
||||
|
||||
/* Unregister HW RNG driver */
|
||||
b43_rng_exit(wl);
|
||||
|
||||
b43_leds_unregister(wl);
|
||||
|
||||
ieee80211_free_hw(wl->hw);
|
||||
|
@ -5541,6 +5543,9 @@ static void b43_ssb_remove(struct ssb_device *sdev)
|
|||
|
||||
b43_one_core_detach(dev);
|
||||
|
||||
/* Unregister HW RNG driver */
|
||||
b43_rng_exit(wl);
|
||||
|
||||
if (list_empty(&wl->devlist)) {
|
||||
b43_leds_unregister(wl);
|
||||
/* Last core on the chip unregistered.
|
||||
|
|
|
@ -3919,6 +3919,7 @@ static void b43legacy_remove(struct ssb_device *dev)
|
|||
* as the ieee80211 unreg will destroy the workqueue. */
|
||||
cancel_work_sync(&wldev->restart_work);
|
||||
cancel_work_sync(&wl->firmware_load);
|
||||
complete(&wldev->fw_load_complete);
|
||||
|
||||
B43legacy_WARN_ON(!wl);
|
||||
if (!wldev->fw.ucode)
|
||||
|
|
|
@ -32,6 +32,7 @@ brcmfmac-objs += \
|
|||
bcdc.o \
|
||||
dhd_common.o \
|
||||
dhd_linux.o \
|
||||
nvram.o \
|
||||
btcoex.o
|
||||
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
|
||||
dhd_sdio.o \
|
||||
|
|
|
@ -287,6 +287,9 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
|||
s32 retry = 0;
|
||||
int ret;
|
||||
|
||||
if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
/*
|
||||
* figure out how to read the register based on address range
|
||||
* 0x00 ~ 0x7FF: function 0 CCCR and FBR
|
||||
|
@ -306,9 +309,12 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
|
|||
usleep_range(1000, 2000);
|
||||
ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz,
|
||||
data, write);
|
||||
} while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
|
||||
} while (ret != 0 && ret != -ENOMEDIUM &&
|
||||
retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
|
||||
|
||||
if (ret != 0)
|
||||
if (ret == -ENOMEDIUM)
|
||||
brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
|
||||
else if (ret != 0)
|
||||
brcmf_err("failed with %d\n", ret);
|
||||
|
||||
return ret;
|
||||
|
@ -320,6 +326,9 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
|
|||
int err = 0, i;
|
||||
u8 addr[3];
|
||||
|
||||
if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
|
||||
return -ENOMEDIUM;
|
||||
|
||||
addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
|
||||
addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
|
||||
addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
|
||||
|
@ -429,6 +438,7 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
bool write, u32 addr, struct sk_buff *pkt)
|
||||
{
|
||||
unsigned int req_sz;
|
||||
int err;
|
||||
|
||||
brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
|
||||
if (brcmf_sdiod_pm_resume_error(sdiodev))
|
||||
|
@ -439,18 +449,18 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
req_sz &= (uint)~3;
|
||||
|
||||
if (write)
|
||||
return sdio_memcpy_toio(sdiodev->func[fn], addr,
|
||||
((u8 *)(pkt->data)),
|
||||
req_sz);
|
||||
err = sdio_memcpy_toio(sdiodev->func[fn], addr,
|
||||
((u8 *)(pkt->data)), req_sz);
|
||||
else if (fn == 1)
|
||||
return sdio_memcpy_fromio(sdiodev->func[fn],
|
||||
((u8 *)(pkt->data)),
|
||||
addr, req_sz);
|
||||
err = sdio_memcpy_fromio(sdiodev->func[fn], ((u8 *)(pkt->data)),
|
||||
addr, req_sz);
|
||||
else
|
||||
/* function 2 read is FIFO operation */
|
||||
return sdio_readsb(sdiodev->func[fn],
|
||||
((u8 *)(pkt->data)), addr,
|
||||
req_sz);
|
||||
err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
|
||||
req_sz);
|
||||
if (err == -ENOMEDIUM)
|
||||
brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -593,7 +603,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);
|
||||
|
||||
ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
|
||||
if (ret != 0) {
|
||||
if (ret == -ENOMEDIUM) {
|
||||
brcmf_bus_change_state(sdiodev->bus_if,
|
||||
BRCMF_BUS_NOMEDIUM);
|
||||
break;
|
||||
} else if (ret != 0) {
|
||||
brcmf_err("CMD53 sg block %s failed %d\n",
|
||||
write ? "write" : "read", ret);
|
||||
ret = -EIO;
|
||||
|
@ -852,8 +866,6 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
|
|||
|
||||
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
|
||||
if (sdiodev->bus) {
|
||||
brcmf_sdio_remove(sdiodev->bus);
|
||||
sdiodev->bus = NULL;
|
||||
|
|
|
@ -17,8 +17,12 @@
|
|||
#ifndef _BRCMF_BUS_H_
|
||||
#define _BRCMF_BUS_H_
|
||||
|
||||
#include "dhd_dbg.h"
|
||||
|
||||
/* The level of bus communication with the dongle */
|
||||
enum brcmf_bus_state {
|
||||
BRCMF_BUS_UNKNOWN, /* Not determined yet */
|
||||
BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */
|
||||
BRCMF_BUS_DOWN, /* Not ready for frame transfers */
|
||||
BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
|
||||
BRCMF_BUS_DATA /* Ready for frame transfers */
|
||||
|
@ -144,6 +148,23 @@ struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)
|
|||
|
||||
return bus->ops->gettxq(bus->dev);
|
||||
}
|
||||
|
||||
static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
|
||||
{
|
||||
return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
|
||||
}
|
||||
|
||||
static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
|
||||
enum brcmf_bus_state new_state)
|
||||
{
|
||||
/* NOMEDIUM is permanent */
|
||||
if (bus->state == BRCMF_BUS_NOMEDIUM)
|
||||
return;
|
||||
|
||||
brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
|
||||
bus->state = new_state;
|
||||
}
|
||||
|
||||
/*
|
||||
* interface functions from common layer
|
||||
*/
|
||||
|
|
|
@ -934,7 +934,7 @@ int brcmf_bus_start(struct device *dev)
|
|||
p2p_ifp = NULL;
|
||||
|
||||
/* signal bus ready */
|
||||
bus_if->state = BRCMF_BUS_DATA;
|
||||
brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
|
||||
|
||||
/* Bus is ready, do any initialization */
|
||||
ret = brcmf_c_preinit_dcmds(ifp);
|
||||
|
@ -1029,6 +1029,8 @@ void brcmf_detach(struct device *dev)
|
|||
/* stop firmware event handling */
|
||||
brcmf_fweh_detach(drvr);
|
||||
|
||||
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
|
||||
|
||||
/* make sure primary interface removed last */
|
||||
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
|
||||
if (drvr->iflist[i]) {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <soc.h>
|
||||
#include "sdio_host.h"
|
||||
#include "sdio_chip.h"
|
||||
#include "nvram.h"
|
||||
|
||||
#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
|
||||
|
||||
|
@ -368,9 +369,7 @@ struct brcmf_sdio_hdrinfo {
|
|||
/* Private data for SDIO bus interaction */
|
||||
struct brcmf_sdio {
|
||||
struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
|
||||
struct chip_info *ci; /* Chip info struct */
|
||||
char *vars; /* Variables (from CIS and/or other) */
|
||||
uint varsz; /* Size of variables buffer */
|
||||
struct brcmf_chip *ci; /* Chip info struct */
|
||||
|
||||
u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
|
||||
|
||||
|
@ -1083,10 +1082,6 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
|
|||
|
||||
/* Clear partial in any case */
|
||||
bus->cur_read.len = 0;
|
||||
|
||||
/* If we can't reach the device, signal failure */
|
||||
if (err)
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
|
||||
/* return total length of buffer chain */
|
||||
|
@ -1683,8 +1678,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
|
|||
bus->rxpending = true;
|
||||
|
||||
for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
|
||||
!bus->rxskip && rxleft &&
|
||||
bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN;
|
||||
!bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
|
||||
rd->seq_num++, rxleft--) {
|
||||
|
||||
/* Handle glomming separately */
|
||||
|
@ -2233,41 +2227,37 @@ static void brcmf_sdio_bus_stop(struct device *dev)
|
|||
bus->watchdog_tsk = NULL;
|
||||
}
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
if (bus_if->state == BRCMF_BUS_DOWN) {
|
||||
sdio_claim_host(sdiodev->func[1]);
|
||||
|
||||
/* Enable clock for device interrupts */
|
||||
brcmf_sdio_bus_sleep(bus, false, false);
|
||||
/* Enable clock for device interrupts */
|
||||
brcmf_sdio_bus_sleep(bus, false, false);
|
||||
|
||||
/* Disable and clear interrupts at the chip level also */
|
||||
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
|
||||
local_hostintmask = bus->hostintmask;
|
||||
bus->hostintmask = 0;
|
||||
/* Disable and clear interrupts at the chip level also */
|
||||
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
|
||||
local_hostintmask = bus->hostintmask;
|
||||
bus->hostintmask = 0;
|
||||
|
||||
/* Change our idea of bus state */
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
/* Force backplane clocks to assure F2 interrupt propagates */
|
||||
saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
&err);
|
||||
if (!err)
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
(saveclk | SBSDIO_FORCE_HT), &err);
|
||||
if (err)
|
||||
brcmf_err("Failed to force clock for F2: err %d\n",
|
||||
err);
|
||||
|
||||
/* Force clocks on backplane to be sure F2 interrupt propagates */
|
||||
saveclk = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_CHIPCLKCSR, &err);
|
||||
if (!err) {
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
|
||||
(saveclk | SBSDIO_FORCE_HT), &err);
|
||||
/* Turn off the bus (F2), free any pending packets */
|
||||
brcmf_dbg(INTR, "disable SDIO interrupts\n");
|
||||
sdio_disable_func(sdiodev->func[SDIO_FUNC_2]);
|
||||
|
||||
/* Clear any pending interrupts now that F2 is disabled */
|
||||
w_sdreg32(bus, local_hostintmask,
|
||||
offsetof(struct sdpcmd_regs, intstatus));
|
||||
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
}
|
||||
if (err)
|
||||
brcmf_err("Failed to force clock for F2: err %d\n", err);
|
||||
|
||||
/* Turn off the bus (F2), free any pending packets */
|
||||
brcmf_dbg(INTR, "disable SDIO interrupts\n");
|
||||
sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
|
||||
|
||||
/* Clear any pending interrupts now that F2 is disabled */
|
||||
w_sdreg32(bus, local_hostintmask,
|
||||
offsetof(struct sdpcmd_regs, intstatus));
|
||||
|
||||
/* Turn off the backplane clock (only) */
|
||||
brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
||||
/* Clear the data packet queues */
|
||||
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
|
||||
|
||||
|
@ -2357,20 +2347,11 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
/* Check for inconsistent device control */
|
||||
devctl = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_DEVICE_CTL, &err);
|
||||
if (err) {
|
||||
brcmf_err("error reading DEVCTL: %d\n", err);
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* Read CSR, if clock on switch to AVAIL, else ignore */
|
||||
clkctl = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_CHIPCLKCSR, &err);
|
||||
if (err) {
|
||||
brcmf_err("error reading CSR: %d\n",
|
||||
err);
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
|
||||
brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
|
||||
devctl, clkctl);
|
||||
|
@ -2378,19 +2359,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
if (SBSDIO_HTAV(clkctl)) {
|
||||
devctl = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_DEVICE_CTL, &err);
|
||||
if (err) {
|
||||
brcmf_err("error reading DEVCTL: %d\n",
|
||||
err);
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
|
||||
devctl, &err);
|
||||
if (err) {
|
||||
brcmf_err("error writing DEVCTL: %d\n",
|
||||
err);
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
bus->clkstate = CLK_AVAIL;
|
||||
}
|
||||
}
|
||||
|
@ -2525,9 +2496,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
txlimit -= framecnt;
|
||||
}
|
||||
|
||||
if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
|
||||
if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
|
||||
brcmf_err("failed backplane access over SDIO, halting operation\n");
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
atomic_set(&bus->intstatus, 0);
|
||||
} else if (atomic_read(&bus->intstatus) ||
|
||||
atomic_read(&bus->ipend) > 0 ||
|
||||
|
@ -3195,46 +3165,69 @@ brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
|
|||
return rxlen ? (int)rxlen : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static bool brcmf_sdio_download_state(struct brcmf_sdio *bus, bool enter)
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
|
||||
u8 *ram_data, uint ram_sz)
|
||||
{
|
||||
struct chip_info *ci = bus->ci;
|
||||
char *ram_cmp;
|
||||
int err;
|
||||
bool ret = true;
|
||||
int address;
|
||||
int offset;
|
||||
int len;
|
||||
|
||||
/* To enter download state, disable ARM and reset SOCRAM.
|
||||
* To exit download state, simply reset ARM (default is RAM boot).
|
||||
*/
|
||||
if (enter) {
|
||||
bus->alp_only = true;
|
||||
/* read back and verify */
|
||||
brcmf_dbg(INFO, "Compare RAM dl & ul at 0x%08x; size=%d\n", ram_addr,
|
||||
ram_sz);
|
||||
ram_cmp = kmalloc(MEMBLOCK, GFP_KERNEL);
|
||||
/* do not proceed while no memory but */
|
||||
if (!ram_cmp)
|
||||
return true;
|
||||
|
||||
brcmf_sdio_chip_enter_download(bus->sdiodev, ci);
|
||||
} else {
|
||||
if (!brcmf_sdio_chip_exit_download(bus->sdiodev, ci, bus->vars,
|
||||
bus->varsz))
|
||||
return false;
|
||||
|
||||
/* Allow HT Clock now that the ARM is running. */
|
||||
bus->alp_only = false;
|
||||
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
|
||||
address = ram_addr;
|
||||
offset = 0;
|
||||
while (offset < ram_sz) {
|
||||
len = ((offset + MEMBLOCK) < ram_sz) ? MEMBLOCK :
|
||||
ram_sz - offset;
|
||||
err = brcmf_sdiod_ramrw(sdiodev, false, address, ram_cmp, len);
|
||||
if (err) {
|
||||
brcmf_err("error %d on reading %d membytes at 0x%08x\n",
|
||||
err, len, address);
|
||||
ret = false;
|
||||
break;
|
||||
} else if (memcmp(ram_cmp, &ram_data[offset], len)) {
|
||||
brcmf_err("Downloaded RAM image is corrupted, block offset is %d, len is %d\n",
|
||||
offset, len);
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
address += len;
|
||||
}
|
||||
|
||||
kfree(ram_cmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else /* DEBUG */
|
||||
static bool
|
||||
brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr,
|
||||
u8 *ram_data, uint ram_sz)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
|
||||
static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int err;
|
||||
int offset;
|
||||
int address;
|
||||
int len;
|
||||
|
||||
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
|
||||
if (fw == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4) !=
|
||||
BRCMF_MAX_CORENUM)
|
||||
memcpy(&bus->ci->rst_vec, fw->data, sizeof(bus->ci->rst_vec));
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
err = 0;
|
||||
offset = 0;
|
||||
|
@ -3247,138 +3240,96 @@ static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus)
|
|||
if (err) {
|
||||
brcmf_err("error %d on writing %d membytes at 0x%08x\n",
|
||||
err, len, address);
|
||||
goto failure;
|
||||
return err;
|
||||
}
|
||||
offset += len;
|
||||
address += len;
|
||||
}
|
||||
|
||||
failure:
|
||||
release_firmware(fw);
|
||||
if (!err)
|
||||
if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase,
|
||||
(u8 *)fw->data, fw->size))
|
||||
err = -EIO;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
|
||||
* and ending in a NUL.
|
||||
* Removes carriage returns, empty lines, comment lines, and converts
|
||||
* newlines to NULs.
|
||||
* Shortens buffer as needed and pads with NULs. End of buffer is marked
|
||||
* by two NULs.
|
||||
*/
|
||||
|
||||
static int brcmf_sdio_strip_nvram(struct brcmf_sdio *bus,
|
||||
const struct firmware *nv)
|
||||
static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus,
|
||||
const struct firmware *nv)
|
||||
{
|
||||
char *varbuf;
|
||||
char *dp;
|
||||
bool findNewline;
|
||||
int column;
|
||||
int ret = 0;
|
||||
uint buf_len, n, len;
|
||||
void *vars;
|
||||
u32 varsz;
|
||||
int address;
|
||||
int err;
|
||||
|
||||
len = nv->size;
|
||||
varbuf = vmalloc(len);
|
||||
if (!varbuf)
|
||||
return -ENOMEM;
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
memcpy(varbuf, nv->data, len);
|
||||
dp = varbuf;
|
||||
vars = brcmf_nvram_strip(nv, &varsz);
|
||||
|
||||
findNewline = false;
|
||||
column = 0;
|
||||
if (vars == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
if (varbuf[n] == 0)
|
||||
break;
|
||||
if (varbuf[n] == '\r')
|
||||
continue;
|
||||
if (findNewline && varbuf[n] != '\n')
|
||||
continue;
|
||||
findNewline = false;
|
||||
if (varbuf[n] == '#') {
|
||||
findNewline = true;
|
||||
continue;
|
||||
}
|
||||
if (varbuf[n] == '\n') {
|
||||
if (column == 0)
|
||||
continue;
|
||||
*dp++ = 0;
|
||||
column = 0;
|
||||
continue;
|
||||
}
|
||||
*dp++ = varbuf[n];
|
||||
column++;
|
||||
}
|
||||
buf_len = dp - varbuf;
|
||||
while (dp < varbuf + n)
|
||||
*dp++ = 0;
|
||||
address = bus->ci->ramsize - varsz + bus->ci->rambase;
|
||||
err = brcmf_sdiod_ramrw(bus->sdiodev, true, address, vars, varsz);
|
||||
if (err)
|
||||
brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
|
||||
err, varsz, address);
|
||||
else if (!brcmf_sdio_verifymemory(bus->sdiodev, address, vars, varsz))
|
||||
err = -EIO;
|
||||
|
||||
kfree(bus->vars);
|
||||
/* roundup needed for download to device */
|
||||
bus->varsz = roundup(buf_len + 1, 4);
|
||||
bus->vars = kmalloc(bus->varsz, GFP_KERNEL);
|
||||
if (bus->vars == NULL) {
|
||||
bus->varsz = 0;
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
brcmf_nvram_free(vars);
|
||||
|
||||
/* copy the processed variables and add null termination */
|
||||
memcpy(bus->vars, varbuf, buf_len);
|
||||
bus->vars[buf_len] = 0;
|
||||
err:
|
||||
vfree(varbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus)
|
||||
{
|
||||
const struct firmware *nv;
|
||||
int ret;
|
||||
|
||||
nv = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
|
||||
if (nv == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
ret = brcmf_sdio_strip_nvram(bus, nv);
|
||||
|
||||
release_firmware(nv);
|
||||
|
||||
return ret;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus)
|
||||
{
|
||||
int bcmerror = -EFAULT;
|
||||
|
||||
const struct firmware *fw;
|
||||
u32 rstvec;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
|
||||
/* Keep arm in reset */
|
||||
if (!brcmf_sdio_download_state(bus, true)) {
|
||||
brcmf_err("error placing ARM core in reset\n");
|
||||
brcmf_sdio_chip_enter_download(bus->sdiodev, bus->ci);
|
||||
|
||||
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_BIN);
|
||||
if (fw == NULL) {
|
||||
bcmerror = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (brcmf_sdio_download_code_file(bus)) {
|
||||
rstvec = get_unaligned_le32(fw->data);
|
||||
brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec);
|
||||
|
||||
bcmerror = brcmf_sdio_download_code_file(bus, fw);
|
||||
release_firmware(fw);
|
||||
if (bcmerror) {
|
||||
brcmf_err("dongle image file download failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (brcmf_sdio_download_nvram(bus)) {
|
||||
fw = brcmf_sdio_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
|
||||
if (fw == NULL) {
|
||||
bcmerror = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
bcmerror = brcmf_sdio_download_nvram(bus, fw);
|
||||
release_firmware(fw);
|
||||
if (bcmerror) {
|
||||
brcmf_err("dongle nvram file download failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Take arm out of reset */
|
||||
if (!brcmf_sdio_download_state(bus, false)) {
|
||||
if (!brcmf_sdio_chip_exit_download(bus->sdiodev, bus->ci, rstvec)) {
|
||||
brcmf_err("error getting out of ARM core reset\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Allow HT Clock now that the ARM is running. */
|
||||
brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
|
||||
bcmerror = 0;
|
||||
|
||||
err:
|
||||
|
@ -3567,9 +3518,11 @@ static int brcmf_sdio_bus_init(struct device *dev)
|
|||
|
||||
/* try to download image and nvram to the dongle */
|
||||
if (bus_if->state == BRCMF_BUS_DOWN) {
|
||||
bus->alp_only = true;
|
||||
err = brcmf_sdio_download_firmware(bus);
|
||||
if (err)
|
||||
return err;
|
||||
bus->alp_only = false;
|
||||
}
|
||||
|
||||
if (!bus->sdiodev->bus_if->drvr)
|
||||
|
@ -3653,7 +3606,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
|
|||
return;
|
||||
}
|
||||
|
||||
if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
|
||||
if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
|
||||
brcmf_err("bus is down. we have nothing to do\n");
|
||||
return;
|
||||
}
|
||||
|
@ -3664,7 +3617,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
|
|||
else
|
||||
if (brcmf_sdio_intr_rstatus(bus)) {
|
||||
brcmf_err("failed backplane access\n");
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
}
|
||||
|
||||
/* Disable additional interrupts (is this needed now)? */
|
||||
|
@ -3779,8 +3731,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
|
|||
u32 reg_val;
|
||||
u32 drivestrength;
|
||||
|
||||
bus->alp_only = true;
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
|
||||
pr_debug("F1 signature read @0x18000000=0x%4x\n",
|
||||
|
@ -3803,6 +3753,11 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/* SDIO register access works so moving
|
||||
* state from UNKNOWN to DOWN.
|
||||
*/
|
||||
brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
|
||||
|
||||
if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci)) {
|
||||
brcmf_err("brcmf_sdio_chip_attach failed!\n");
|
||||
goto fail;
|
||||
|
@ -4026,7 +3981,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
/* Disable F2 to clear any intermediate frame state on the dongle */
|
||||
sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
|
||||
|
||||
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
||||
bus->rxflow = false;
|
||||
|
||||
/* Done with backplane-dependent accesses, can drop clock... */
|
||||
|
@ -4082,17 +4036,26 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
|
|||
}
|
||||
|
||||
if (bus->ci) {
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
|
||||
/* Leave the device in state where it is
|
||||
* 'quiet'. This is done by putting it in
|
||||
* download_state which essentially resets
|
||||
* all necessary cores.
|
||||
*/
|
||||
msleep(20);
|
||||
brcmf_sdio_chip_enter_download(bus->sdiodev,
|
||||
bus->ci);
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
brcmf_sdio_chip_detach(&bus->ci);
|
||||
}
|
||||
|
||||
brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
|
||||
kfree(bus->rxbuf);
|
||||
kfree(bus->hdrbuf);
|
||||
kfree(bus->vars);
|
||||
kfree(bus);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Broadcom Corporation
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "nvram.h"
|
||||
|
||||
/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a file
|
||||
* and ending in a NUL. Removes carriage returns, empty lines, comment lines,
|
||||
* and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
|
||||
* End of buffer is completed with token identifying length of buffer.
|
||||
*/
|
||||
void *brcmf_nvram_strip(const struct firmware *nv, u32 *new_length)
|
||||
{
|
||||
u8 *nvram;
|
||||
u32 i;
|
||||
u32 len;
|
||||
u32 column;
|
||||
u8 val;
|
||||
bool comment;
|
||||
u32 token;
|
||||
__le32 token_le;
|
||||
|
||||
/* Alloc for extra 0 byte + roundup by 4 + length field */
|
||||
nvram = kmalloc(nv->size + 1 + 3 + sizeof(token_le), GFP_KERNEL);
|
||||
if (!nvram)
|
||||
return NULL;
|
||||
|
||||
len = 0;
|
||||
column = 0;
|
||||
comment = false;
|
||||
for (i = 0; i < nv->size; i++) {
|
||||
val = nv->data[i];
|
||||
if (val == 0)
|
||||
break;
|
||||
if (val == '\r')
|
||||
continue;
|
||||
if (comment && (val != '\n'))
|
||||
continue;
|
||||
comment = false;
|
||||
if (val == '#') {
|
||||
comment = true;
|
||||
continue;
|
||||
}
|
||||
if (val == '\n') {
|
||||
if (column == 0)
|
||||
continue;
|
||||
nvram[len] = 0;
|
||||
len++;
|
||||
column = 0;
|
||||
continue;
|
||||
}
|
||||
nvram[len] = val;
|
||||
len++;
|
||||
column++;
|
||||
}
|
||||
column = len;
|
||||
*new_length = roundup(len + 1, 4);
|
||||
while (column != *new_length) {
|
||||
nvram[column] = 0;
|
||||
column++;
|
||||
}
|
||||
|
||||
token = *new_length / 4;
|
||||
token = (~token << 16) | (token & 0x0000FFFF);
|
||||
token_le = cpu_to_le32(token);
|
||||
|
||||
memcpy(&nvram[*new_length], &token_le, sizeof(token_le));
|
||||
*new_length += sizeof(token_le);
|
||||
|
||||
return nvram;
|
||||
}
|
||||
|
||||
void brcmf_nvram_free(void *nvram)
|
||||
{
|
||||
kfree(nvram);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Broadcom Corporation
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef BRCMFMAC_NVRAM_H
|
||||
#define BRCMFMAC_NVRAM_H
|
||||
|
||||
|
||||
void *brcmf_nvram_strip(const struct firmware *nv, u32 *new_length);
|
||||
void brcmf_nvram_free(void *nvram);
|
||||
|
||||
|
||||
#endif /* BRCMFMAC_NVRAM_H */
|
|
@ -51,6 +51,9 @@
|
|||
#define BCM43143_CORE_ARM_BASE 0x18003000
|
||||
#define BCM43143_RAMSIZE 0x70000
|
||||
|
||||
/* All D11 cores, ID 0x812 */
|
||||
#define BCM43xx_CORE_D11_BASE 0x18001000
|
||||
|
||||
#define SBCOREREV(sbidh) \
|
||||
((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
|
||||
((sbidh) & SSB_IDHIGH_RCLO))
|
||||
|
@ -66,6 +69,10 @@
|
|||
/* ARM CR4 core specific control flag bits */
|
||||
#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
|
||||
|
||||
/* D11 core specific control flag bits */
|
||||
#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
|
||||
#define D11_BCMA_IOCTL_PHYRESET 0x0008
|
||||
|
||||
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
|
||||
/* SDIO Pad drive strength to select value mappings */
|
||||
struct sdiod_drive_str {
|
||||
|
@ -111,7 +118,7 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
|
|||
};
|
||||
|
||||
u8
|
||||
brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
|
||||
brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid)
|
||||
{
|
||||
u8 idx;
|
||||
|
||||
|
@ -124,7 +131,7 @@ brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
|
|||
|
||||
static u32
|
||||
brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid)
|
||||
struct brcmf_chip *ci, u16 coreid)
|
||||
{
|
||||
u32 regdata;
|
||||
u8 idx;
|
||||
|
@ -139,7 +146,7 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static u32
|
||||
brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid)
|
||||
struct brcmf_chip *ci, u16 coreid)
|
||||
{
|
||||
u8 idx;
|
||||
|
||||
|
@ -150,7 +157,7 @@ brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static bool
|
||||
brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid)
|
||||
struct brcmf_chip *ci, u16 coreid)
|
||||
{
|
||||
u32 regdata;
|
||||
u8 idx;
|
||||
|
@ -169,7 +176,7 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static bool
|
||||
brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid)
|
||||
struct brcmf_chip *ci, u16 coreid)
|
||||
{
|
||||
u32 regdata;
|
||||
u8 idx;
|
||||
|
@ -193,7 +200,8 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static void
|
||||
brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits)
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits)
|
||||
{
|
||||
u32 regdata, base;
|
||||
u8 idx;
|
||||
|
@ -279,52 +287,48 @@ brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static void
|
||||
brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits)
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits)
|
||||
{
|
||||
u8 idx;
|
||||
u32 regdata;
|
||||
u32 wrapbase;
|
||||
|
||||
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
|
||||
if (idx == BRCMF_MAX_CORENUM)
|
||||
return;
|
||||
|
||||
wrapbase = ci->c_inf[idx].wrapbase;
|
||||
|
||||
/* if core is already in reset, just return */
|
||||
regdata = brcmf_sdiod_regrl(sdiodev,
|
||||
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
|
||||
NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL);
|
||||
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
|
||||
return;
|
||||
|
||||
/* ensure no pending backplane operation
|
||||
* 300uc should be sufficient for backplane ops to be finish
|
||||
* extra 10ms is taken into account for firmware load stage
|
||||
* after 10300us carry on disabling the core anyway
|
||||
*/
|
||||
SPINWAIT(brcmf_sdiod_regrl(sdiodev,
|
||||
ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
|
||||
NULL), 10300);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev,
|
||||
ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
|
||||
NULL);
|
||||
if (regdata)
|
||||
brcmf_err("disabling core 0x%x with reset status %x\n",
|
||||
coreid, regdata);
|
||||
/* configure reset */
|
||||
brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
|
||||
BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
|
||||
|
||||
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
|
||||
/* put in reset */
|
||||
brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL,
|
||||
BCMA_RESET_CTL_RESET, NULL);
|
||||
udelay(1);
|
||||
|
||||
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
core_bits, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
NULL);
|
||||
usleep_range(10, 20);
|
||||
|
||||
/* wait till reset is 1 */
|
||||
SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) !=
|
||||
BCMA_RESET_CTL_RESET, 300);
|
||||
|
||||
/* post reset configure */
|
||||
brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
|
||||
BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits)
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits, u32 post_resetbits)
|
||||
{
|
||||
u32 regdata;
|
||||
u8 idx;
|
||||
|
@ -337,7 +341,8 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
|
|||
* Must do the disable sequence first to work for
|
||||
* arbitrary current core state.
|
||||
*/
|
||||
brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
|
||||
brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, pre_resetbits,
|
||||
in_resetbits);
|
||||
|
||||
/*
|
||||
* Now do the initialization sequence.
|
||||
|
@ -390,40 +395,37 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
|
|||
|
||||
static void
|
||||
brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits)
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits, u32 post_resetbits)
|
||||
{
|
||||
u8 idx;
|
||||
u32 regdata;
|
||||
u32 wrapbase;
|
||||
|
||||
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
|
||||
if (idx == BRCMF_MAX_CORENUM)
|
||||
return;
|
||||
|
||||
wrapbase = ci->c_inf[idx].wrapbase;
|
||||
|
||||
/* must disable first to work for arbitrary current core state */
|
||||
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
|
||||
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, pre_resetbits,
|
||||
in_resetbits);
|
||||
|
||||
/* now do initialization sequence */
|
||||
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
NULL);
|
||||
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
|
||||
0, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev,
|
||||
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
|
||||
NULL);
|
||||
udelay(1);
|
||||
while (brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) &
|
||||
BCMA_RESET_CTL_RESET) {
|
||||
brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, 0, NULL);
|
||||
usleep_range(40, 60);
|
||||
}
|
||||
|
||||
brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
core_bits | BCMA_IOCTL_CLK, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
|
||||
NULL);
|
||||
udelay(1);
|
||||
brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, post_resetbits |
|
||||
BCMA_IOCTL_CLK, NULL);
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* safety check for chipinfo */
|
||||
static int brcmf_sdio_chip_cichk(struct chip_info *ci)
|
||||
static int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
|
||||
{
|
||||
u8 core_idx;
|
||||
|
||||
|
@ -450,189 +452,213 @@ static int brcmf_sdio_chip_cichk(struct chip_info *ci)
|
|||
return 0;
|
||||
}
|
||||
#else /* DEBUG */
|
||||
static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
|
||||
static inline int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci)
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
u32 regdata;
|
||||
int ret;
|
||||
u32 socitype;
|
||||
|
||||
/* Get CC core rev
|
||||
* Chipid is assume to be at offset 0 from regs arg
|
||||
* Chipid is assume to be at offset 0 from SI_ENUM_BASE
|
||||
* For different chiptypes or old sdio hosts w/o chipcommon,
|
||||
* other ways of recognition should be added here.
|
||||
*/
|
||||
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
|
||||
ci->c_inf[0].base = SI_ENUM_BASE;
|
||||
regdata = brcmf_sdiod_regrl(sdiodev,
|
||||
CORE_CC_REG(ci->c_inf[0].base, chipid),
|
||||
CORE_CC_REG(SI_ENUM_BASE, chipid),
|
||||
NULL);
|
||||
ci->chip = regdata & CID_ID_MASK;
|
||||
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
|
||||
if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
|
||||
ci->chiprev >= 2)
|
||||
ci->chip = BCM4339_CHIP_ID;
|
||||
ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
|
||||
socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
|
||||
|
||||
brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
|
||||
brcmf_dbg(INFO, "found %s chip: id=0x%x, rev=%d\n",
|
||||
socitype == SOCI_SB ? "SB" : "AXI", ci->chip, ci->chiprev);
|
||||
|
||||
/* Address of cores for new chips should be added here */
|
||||
switch (ci->chip) {
|
||||
case BCM43143_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
|
||||
ci->c_inf[0].cib = 0x2b000000;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
|
||||
ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
|
||||
ci->c_inf[1].cib = 0x18000000;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
|
||||
ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
|
||||
ci->c_inf[2].cib = 0x14000000;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
|
||||
ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
|
||||
ci->c_inf[3].cib = 0x07000000;
|
||||
ci->ramsize = BCM43143_RAMSIZE;
|
||||
break;
|
||||
case BCM43241_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2a084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0e004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x14080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x07004211;
|
||||
ci->ramsize = 0x90000;
|
||||
break;
|
||||
case BCM4329_CHIP_ID:
|
||||
if (socitype == SOCI_SB) {
|
||||
if (ci->chip != BCM4329_CHIP_ID) {
|
||||
brcmf_err("SB chip is not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ci->iscoreup = brcmf_sdio_sb_iscoreup;
|
||||
ci->corerev = brcmf_sdio_sb_corerev;
|
||||
ci->coredisable = brcmf_sdio_sb_coredisable;
|
||||
ci->resetcore = brcmf_sdio_sb_resetcore;
|
||||
|
||||
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
|
||||
ci->c_inf[0].base = SI_ENUM_BASE;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->ramsize = BCM4329_RAMSIZE;
|
||||
break;
|
||||
case BCM4330_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x27004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x07004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x0d080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x03004211;
|
||||
ci->ramsize = 0x48000;
|
||||
break;
|
||||
case BCM4334_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x29004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0d004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x13080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x07004211;
|
||||
ci->ramsize = 0x80000;
|
||||
break;
|
||||
case BCM4335_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2b084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18005000;
|
||||
ci->c_inf[1].wrapbase = 0x18105000;
|
||||
ci->c_inf[1].cib = 0x0f004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
|
||||
ci->c_inf[2].base = 0x18002000;
|
||||
ci->c_inf[2].wrapbase = 0x18102000;
|
||||
ci->c_inf[2].cib = 0x01084411;
|
||||
ci->ramsize = 0xc0000;
|
||||
ci->rambase = 0x180000;
|
||||
break;
|
||||
case BCM4339_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2e084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18005000;
|
||||
ci->c_inf[1].wrapbase = 0x18105000;
|
||||
ci->c_inf[1].cib = 0x15004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
|
||||
ci->c_inf[2].base = 0x18002000;
|
||||
ci->c_inf[2].wrapbase = 0x18102000;
|
||||
ci->c_inf[2].cib = 0x04084411;
|
||||
ci->ramsize = 0xc0000;
|
||||
ci->rambase = 0x180000;
|
||||
break;
|
||||
case BCM43362_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x27004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0a004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x08080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x03004211;
|
||||
ci->ramsize = 0x3C000;
|
||||
break;
|
||||
default:
|
||||
brcmf_err("chipid 0x%x is not supported\n", ci->chip);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = brcmf_sdio_chip_cichk(ci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (ci->socitype) {
|
||||
case SOCI_SB:
|
||||
ci->iscoreup = brcmf_sdio_sb_iscoreup;
|
||||
ci->corerev = brcmf_sdio_sb_corerev;
|
||||
ci->coredisable = brcmf_sdio_sb_coredisable;
|
||||
ci->resetcore = brcmf_sdio_sb_resetcore;
|
||||
break;
|
||||
case SOCI_AI:
|
||||
} else if (socitype == SOCI_AI) {
|
||||
ci->iscoreup = brcmf_sdio_ai_iscoreup;
|
||||
ci->corerev = brcmf_sdio_ai_corerev;
|
||||
ci->coredisable = brcmf_sdio_ai_coredisable;
|
||||
ci->resetcore = brcmf_sdio_ai_resetcore;
|
||||
break;
|
||||
default:
|
||||
brcmf_err("socitype %u not supported\n", ci->socitype);
|
||||
|
||||
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
|
||||
ci->c_inf[0].base = SI_ENUM_BASE;
|
||||
|
||||
/* Address of cores for new chips should be added here */
|
||||
switch (ci->chip) {
|
||||
case BCM43143_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
|
||||
ci->c_inf[0].cib = 0x2b000000;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
|
||||
ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
|
||||
ci->c_inf[1].cib = 0x18000000;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
|
||||
ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
|
||||
ci->c_inf[2].cib = 0x14000000;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
|
||||
ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
|
||||
ci->c_inf[3].cib = 0x07000000;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
|
||||
ci->ramsize = BCM43143_RAMSIZE;
|
||||
break;
|
||||
case BCM43241_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2a084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0e004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x14080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x07004211;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
|
||||
ci->ramsize = 0x90000;
|
||||
break;
|
||||
case BCM4330_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x27004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x07004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x0d080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x03004211;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
|
||||
ci->ramsize = 0x48000;
|
||||
break;
|
||||
case BCM4334_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x29004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0d004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x13080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x07004211;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
|
||||
ci->ramsize = 0x80000;
|
||||
break;
|
||||
case BCM4335_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2b084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18005000;
|
||||
ci->c_inf[1].wrapbase = 0x18105000;
|
||||
ci->c_inf[1].cib = 0x0f004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
|
||||
ci->c_inf[2].base = 0x18002000;
|
||||
ci->c_inf[2].wrapbase = 0x18102000;
|
||||
ci->c_inf[2].cib = 0x01084411;
|
||||
ci->c_inf[3].id = BCMA_CORE_80211;
|
||||
ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
|
||||
ci->ramsize = 0xc0000;
|
||||
ci->rambase = 0x180000;
|
||||
break;
|
||||
case BCM43362_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x27004211;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18002000;
|
||||
ci->c_inf[1].wrapbase = 0x18102000;
|
||||
ci->c_inf[1].cib = 0x0a004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
|
||||
ci->c_inf[2].base = 0x18004000;
|
||||
ci->c_inf[2].wrapbase = 0x18104000;
|
||||
ci->c_inf[2].cib = 0x08080401;
|
||||
ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
|
||||
ci->c_inf[3].base = 0x18003000;
|
||||
ci->c_inf[3].wrapbase = 0x18103000;
|
||||
ci->c_inf[3].cib = 0x03004211;
|
||||
ci->c_inf[4].id = BCMA_CORE_80211;
|
||||
ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
|
||||
ci->ramsize = 0x3C000;
|
||||
break;
|
||||
case BCM4339_CHIP_ID:
|
||||
ci->c_inf[0].wrapbase = 0x18100000;
|
||||
ci->c_inf[0].cib = 0x2e084411;
|
||||
ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
|
||||
ci->c_inf[1].base = 0x18005000;
|
||||
ci->c_inf[1].wrapbase = 0x18105000;
|
||||
ci->c_inf[1].cib = 0x15004211;
|
||||
ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
|
||||
ci->c_inf[2].base = 0x18002000;
|
||||
ci->c_inf[2].wrapbase = 0x18102000;
|
||||
ci->c_inf[2].cib = 0x04084411;
|
||||
ci->c_inf[3].id = BCMA_CORE_80211;
|
||||
ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
|
||||
ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
|
||||
ci->ramsize = 0xc0000;
|
||||
ci->rambase = 0x180000;
|
||||
break;
|
||||
default:
|
||||
brcmf_err("AXI chip is not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
brcmf_err("chip backplane type %u is not supported\n",
|
||||
socitype);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return brcmf_sdio_chip_cichk(ci);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -682,7 +708,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
|
|||
|
||||
static void
|
||||
brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci)
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
u32 base = ci->c_inf[0].base;
|
||||
|
||||
|
@ -713,19 +739,18 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
|
|||
* Make sure any on-chip ARM is off (in case strapping is wrong),
|
||||
* or downloaded code was already running.
|
||||
*/
|
||||
ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
|
||||
ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
|
||||
}
|
||||
|
||||
int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info **ci_ptr)
|
||||
struct brcmf_chip **ci_ptr)
|
||||
{
|
||||
int ret;
|
||||
struct chip_info *ci;
|
||||
struct brcmf_chip *ci;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
/* alloc chip_info_t */
|
||||
ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
|
||||
ci = kzalloc(sizeof(*ci), GFP_ATOMIC);
|
||||
if (!ci)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -753,7 +778,7 @@ err:
|
|||
}
|
||||
|
||||
void
|
||||
brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
|
||||
brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr)
|
||||
{
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
|
@ -772,7 +797,7 @@ static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
|
|||
|
||||
void
|
||||
brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u32 drivestrength)
|
||||
struct brcmf_chip *ci, u32 drivestrength)
|
||||
{
|
||||
const struct sdiod_drive_str *str_tab = NULL;
|
||||
u32 str_mask;
|
||||
|
@ -842,107 +867,19 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
|
||||
char *nvram_dat, uint nvram_sz)
|
||||
{
|
||||
char *nvram_ularray;
|
||||
int err;
|
||||
bool ret = true;
|
||||
|
||||
/* read back and verify */
|
||||
brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz);
|
||||
nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL);
|
||||
/* do not proceed while no memory but */
|
||||
if (!nvram_ularray)
|
||||
return true;
|
||||
|
||||
/* Upload image to verify downloaded contents. */
|
||||
memset(nvram_ularray, 0xaa, nvram_sz);
|
||||
|
||||
/* Read the vars list to temp buffer for comparison */
|
||||
err = brcmf_sdiod_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
|
||||
nvram_sz);
|
||||
if (err) {
|
||||
brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
|
||||
err, nvram_sz, nvram_addr);
|
||||
} else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) {
|
||||
brcmf_err("Downloaded NVRAM image is corrupted\n");
|
||||
ret = false;
|
||||
}
|
||||
kfree(nvram_ularray);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else /* DEBUG */
|
||||
static inline bool
|
||||
brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
|
||||
char *nvram_dat, uint nvram_sz)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci,
|
||||
char *nvram_dat, uint nvram_sz)
|
||||
{
|
||||
int err;
|
||||
u32 nvram_addr;
|
||||
u32 token;
|
||||
__le32 token_le;
|
||||
|
||||
nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
|
||||
|
||||
/* Write the vars list */
|
||||
err = brcmf_sdiod_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
|
||||
if (err) {
|
||||
brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
|
||||
err, nvram_sz, nvram_addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr,
|
||||
nvram_dat, nvram_sz))
|
||||
return false;
|
||||
|
||||
/* generate token:
|
||||
* nvram size, converted to words, in lower 16-bits, checksum
|
||||
* in upper 16-bits.
|
||||
*/
|
||||
token = nvram_sz / 4;
|
||||
token = (~token << 16) | (token & 0x0000FFFF);
|
||||
token_le = cpu_to_le32(token);
|
||||
|
||||
brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize);
|
||||
brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n",
|
||||
nvram_addr, nvram_sz, token);
|
||||
|
||||
/* Write the length token to the last word */
|
||||
if (brcmf_sdiod_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
|
||||
(u8 *)&token_le, 4))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci)
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
u32 zeros = 0;
|
||||
|
||||
ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
|
||||
|
||||
/* clear length token */
|
||||
brcmf_sdiod_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
|
||||
ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
|
||||
D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
|
||||
D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0, 0, 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
||||
char *nvram_dat, uint nvram_sz)
|
||||
static bool brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev,
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
u8 core_idx;
|
||||
u32 reg_addr;
|
||||
|
@ -952,38 +889,45 @@ brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
|
||||
return false;
|
||||
|
||||
/* clear all interrupts */
|
||||
core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
|
||||
reg_addr = ci->c_inf[core_idx].base;
|
||||
reg_addr += offsetof(struct sdpcmd_regs, intstatus);
|
||||
brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
|
||||
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci)
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
|
||||
ARMCR4_BCMA_IOCTL_CPUHALT);
|
||||
u8 idx;
|
||||
u32 regdata;
|
||||
u32 wrapbase;
|
||||
idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
|
||||
|
||||
if (idx == BRCMF_MAX_CORENUM)
|
||||
return;
|
||||
|
||||
wrapbase = ci->c_inf[idx].wrapbase;
|
||||
regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
|
||||
regdata &= ARMCR4_BCMA_IOCTL_CPUHALT;
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, regdata,
|
||||
ARMCR4_BCMA_IOCTL_CPUHALT, ARMCR4_BCMA_IOCTL_CPUHALT);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
|
||||
D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
|
||||
D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
|
||||
}
|
||||
|
||||
static bool
|
||||
brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
||||
char *nvram_dat, uint nvram_sz)
|
||||
static bool brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev,
|
||||
struct brcmf_chip *ci, u32 rstvec)
|
||||
{
|
||||
u8 core_idx;
|
||||
u32 reg_addr;
|
||||
|
||||
if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
|
||||
return false;
|
||||
|
||||
/* clear all interrupts */
|
||||
core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
|
||||
reg_addr = ci->c_inf[core_idx].base;
|
||||
|
@ -991,17 +935,18 @@ brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
|||
brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
|
||||
|
||||
/* Write reset vector to address 0 */
|
||||
brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
|
||||
sizeof(ci->rst_vec));
|
||||
brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
|
||||
sizeof(rstvec));
|
||||
|
||||
/* restore ARM */
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
|
||||
ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT,
|
||||
0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci)
|
||||
struct brcmf_chip *ci)
|
||||
{
|
||||
u8 arm_core_idx;
|
||||
|
||||
|
@ -1015,15 +960,13 @@ void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
|
|||
}
|
||||
|
||||
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, char *nvram_dat,
|
||||
uint nvram_sz)
|
||||
struct brcmf_chip *ci, u32 rstvec)
|
||||
{
|
||||
u8 arm_core_idx;
|
||||
|
||||
arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
|
||||
if (BRCMF_MAX_CORENUM != arm_core_idx)
|
||||
return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat,
|
||||
nvram_sz);
|
||||
return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
|
||||
|
||||
return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, nvram_dat, nvram_sz);
|
||||
return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
#define BRCMF_MAX_CORENUM 6
|
||||
|
||||
struct chip_core_info {
|
||||
struct brcmf_core {
|
||||
u16 id;
|
||||
u16 rev;
|
||||
u32 base;
|
||||
|
@ -63,27 +63,28 @@ struct chip_core_info {
|
|||
u32 cib;
|
||||
};
|
||||
|
||||
struct chip_info {
|
||||
struct brcmf_chip {
|
||||
u32 chip;
|
||||
u32 chiprev;
|
||||
u32 socitype;
|
||||
/* core info */
|
||||
/* always put chipcommon core at 0, bus core at 1 */
|
||||
struct chip_core_info c_inf[BRCMF_MAX_CORENUM];
|
||||
struct brcmf_core c_inf[BRCMF_MAX_CORENUM];
|
||||
u32 pmurev;
|
||||
u32 pmucaps;
|
||||
u32 ramsize;
|
||||
u32 rambase;
|
||||
u32 rst_vec; /* reset vertor for ARM CR4 core */
|
||||
|
||||
bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
||||
bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
|
||||
u16 coreid);
|
||||
u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
|
||||
u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct brcmf_chip *ci,
|
||||
u16 coreid);
|
||||
void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits);
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits);
|
||||
void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u16 coreid, u32 core_bits);
|
||||
struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
|
||||
u32 in_resetbits, u32 post_resetbits);
|
||||
};
|
||||
|
||||
struct sbconfig {
|
||||
|
@ -216,15 +217,15 @@ struct sdpcmd_regs {
|
|||
};
|
||||
|
||||
int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info **ci_ptr);
|
||||
void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
|
||||
struct brcmf_chip **ci_ptr);
|
||||
void brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr);
|
||||
void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, u32 drivestrength);
|
||||
u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
|
||||
struct brcmf_chip *ci,
|
||||
u32 drivestrength);
|
||||
u8 brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid);
|
||||
void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci);
|
||||
struct brcmf_chip *ci);
|
||||
bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
|
||||
struct chip_info *ci, char *nvram_dat,
|
||||
uint nvram_sz);
|
||||
struct brcmf_chip *ci, u32 rstvec);
|
||||
|
||||
#endif /* _BRCMFMAC_SDIO_CHIP_H_ */
|
||||
|
|
|
@ -522,10 +522,10 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
|
|||
/* update state of upper layer */
|
||||
if (state == BRCMFMAC_USB_STATE_DOWN) {
|
||||
brcmf_dbg(USB, "DBUS is down\n");
|
||||
bcmf_bus->state = BRCMF_BUS_DOWN;
|
||||
brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);
|
||||
} else if (state == BRCMFMAC_USB_STATE_UP) {
|
||||
brcmf_dbg(USB, "DBUS is up\n");
|
||||
bcmf_bus->state = BRCMF_BUS_DATA;
|
||||
brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);
|
||||
} else {
|
||||
brcmf_dbg(USB, "DBUS current state=%d\n", state);
|
||||
}
|
||||
|
|
|
@ -2989,6 +2989,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
|
|||
}
|
||||
|
||||
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
|
||||
cfg->escan_info.run = brcmf_run_escan;
|
||||
err = brcmf_do_escan(cfg, wiphy, ifp, request);
|
||||
if (err) {
|
||||
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
|
||||
|
|
|
@ -1071,7 +1071,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
|
|||
hw->max_rates = 2; /* Primary rate and 1 fallback rate */
|
||||
|
||||
/* channel change time is dependent on chip and band */
|
||||
hw->channel_change_time = 7 * 1000;
|
||||
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
|
|
@ -7108,7 +7108,6 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
|
|||
struct sk_buff *p,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
int preamble;
|
||||
int channel;
|
||||
u32 rspec;
|
||||
unsigned char *plcp;
|
||||
|
@ -7191,7 +7190,6 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
|
|||
rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;
|
||||
|
||||
/* Determine short preamble and rate_idx */
|
||||
preamble = 0;
|
||||
if (is_cck_rate(rspec)) {
|
||||
if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
|
||||
rx_status->flag |= RX_FLAG_SHORTPRE;
|
||||
|
|
|
@ -301,7 +301,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
|||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
||||
hw->channel_change_time = 1000; /* TODO: find actual value */
|
||||
hw->queues = 4;
|
||||
|
||||
priv->rts_threshold = -1;
|
||||
|
|
|
@ -406,9 +406,8 @@ static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
{
|
||||
struct iwl_resume_data *resume_data = data;
|
||||
struct iwl_priv *priv = resume_data->priv;
|
||||
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
|
||||
if (len - 4 != sizeof(*resume_data->cmd)) {
|
||||
if (iwl_rx_packet_payload_len(pkt) != sizeof(*resume_data->cmd)) {
|
||||
IWL_ERR(priv, "rx wrong size data\n");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -205,8 +205,7 @@ static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
|
|||
struct iwl_device_cmd *cmd)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
u32 __maybe_unused len =
|
||||
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
u32 __maybe_unused len = iwl_rx_packet_len(pkt);
|
||||
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
|
||||
"notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
|
||||
iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
|
||||
|
@ -457,7 +456,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
|
|||
const int reg_recalib_period = 60;
|
||||
int change;
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
u32 len = iwl_rx_packet_payload_len(pkt);
|
||||
__le32 *flag;
|
||||
struct statistics_general_common *common;
|
||||
struct statistics_rx_non_phy *rx_non_phy;
|
||||
|
@ -467,8 +466,6 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
|
|||
struct statistics_tx *tx;
|
||||
struct statistics_bt_activity *bt_activity;
|
||||
|
||||
len -= sizeof(struct iwl_cmd_header); /* skip header */
|
||||
|
||||
IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
|
||||
len);
|
||||
|
||||
|
|
|
@ -388,7 +388,6 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
|
|||
{
|
||||
struct iwl_priv *priv = data;
|
||||
struct iwl_calib_hdr *hdr;
|
||||
int len;
|
||||
|
||||
if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
|
||||
WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
|
||||
|
@ -396,12 +395,8 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
|
|||
}
|
||||
|
||||
hdr = (struct iwl_calib_hdr *)pkt->data;
|
||||
len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
|
||||
/* reduce the size by the length field itself */
|
||||
len -= sizeof(__le32);
|
||||
|
||||
if (iwl_calib_set(priv, hdr, len))
|
||||
if (iwl_calib_set(priv, hdr, iwl_rx_packet_payload_len(pkt)))
|
||||
IWL_ERR(priv, "Failed to record calibration data %d\n",
|
||||
hdr->op_code);
|
||||
|
||||
|
|
|
@ -264,14 +264,13 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
struct ieee80211_sta_vht_cap *vht_cap)
|
||||
{
|
||||
int num_ants = num_of_ant(data->valid_rx_ant);
|
||||
int bf_sts_cap = num_ants - 1;
|
||||
|
||||
vht_cap->vht_supported = true;
|
||||
|
||||
vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_1 |
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
||||
bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
|
||||
3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
|
||||
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
|
||||
if (num_ants > 1)
|
||||
|
@ -290,9 +289,6 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
|
||||
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
|
||||
|
||||
/* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
|
||||
vht_cap->vht_mcs.rx_highest = cpu_to_le16(780);
|
||||
|
||||
if (num_ants == 1 ||
|
||||
cfg->rx_with_siso_diversity) {
|
||||
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
|
||||
|
@ -300,12 +296,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
/* this works because NOT_SUPPORTED == 3 */
|
||||
vht_cap->vht_mcs.rx_mcs_map |=
|
||||
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
|
||||
/* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
|
||||
vht_cap->vht_mcs.rx_highest = cpu_to_le16(390);
|
||||
}
|
||||
|
||||
vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
|
||||
vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
|
||||
}
|
||||
|
||||
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
|
|
|
@ -277,4 +277,8 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
|
|||
|
||||
/*********************** END TX SCHEDULER *************************************/
|
||||
|
||||
/* Oscillator clock */
|
||||
#define OSC_CLK (0xa04068)
|
||||
#define OSC_CLK_FORCE_CONTROL (0x8)
|
||||
|
||||
#endif /* __iwl_prph_h__ */
|
||||
|
|
|
@ -176,6 +176,16 @@ struct iwl_rx_packet {
|
|||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
static inline u32 iwl_rx_packet_len(const struct iwl_rx_packet *pkt)
|
||||
{
|
||||
return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
}
|
||||
|
||||
static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
|
||||
{
|
||||
return iwl_rx_packet_len(pkt) - sizeof(pkt->hdr);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum CMD_MODE - how to send the host commands ?
|
||||
*
|
||||
|
|
|
@ -886,8 +886,7 @@ static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
size -= sizeof(cmd.resp_pkt->hdr);
|
||||
size = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
if (size < sizeof(__le16)) {
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
|
@ -1211,9 +1210,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
if (ret)
|
||||
goto out;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) &
|
||||
FH_RSCSR_FRAME_SIZE_MSK;
|
||||
if (len >= sizeof(u32) * 2) {
|
||||
len = iwl_rx_packet_payload_len(d3_cfg_cmd.resp_pkt);
|
||||
if (len >= sizeof(u32)) {
|
||||
mvm->d3_test_pme_ptr =
|
||||
le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
|
||||
}
|
||||
|
@ -1668,8 +1666,8 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
else
|
||||
status_size = sizeof(struct iwl_wowlan_status_v4);
|
||||
|
||||
len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
if (len - sizeof(struct iwl_cmd_header) < status_size) {
|
||||
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
if (len < status_size) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
@ -1704,8 +1702,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
status.wake_packet = status_v4->wake_packet;
|
||||
}
|
||||
|
||||
if (len - sizeof(struct iwl_cmd_header) !=
|
||||
status_size + ALIGN(status.wake_packet_bufsize, 4)) {
|
||||
if (len != status_size + ALIGN(status.wake_packet_bufsize, 4)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
|
|||
ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
|
||||
len = img->sec[IWL_UCODE_SECTION_DATA].len;
|
||||
|
||||
if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
|
||||
if (mvm->dbgfs_sram_len) {
|
||||
ofs = mvm->dbgfs_sram_offset;
|
||||
len = mvm->dbgfs_sram_len;
|
||||
}
|
||||
|
|
|
@ -97,9 +97,6 @@ enum iwl_sta_flags {
|
|||
STA_FLG_FLG_ANT_B),
|
||||
|
||||
STA_FLG_PS = BIT(8),
|
||||
STA_FLG_INVALID = BIT(9),
|
||||
STA_FLG_DLP_EN = BIT(10),
|
||||
STA_FLG_SET_ALL_KEYS = BIT(11),
|
||||
STA_FLG_DRAIN_FLOW = BIT(12),
|
||||
STA_FLG_PAN = BIT(13),
|
||||
STA_FLG_CLASS_AUTH = BIT(14),
|
||||
|
|
|
@ -262,9 +262,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
|
||||
|
||||
/* currently FW API supports only one optional cipher scheme */
|
||||
if (mvm->fw->cs->cipher) {
|
||||
if (mvm->fw->cs[0].cipher) {
|
||||
mvm->hw->n_cipher_schemes = 1;
|
||||
mvm->hw->cipher_schemes = mvm->fw->cs;
|
||||
mvm->hw->cipher_schemes = &mvm->fw->cs[0];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -944,6 +944,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
}
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT,
|
||||
IEEE80211_SMPS_AUTOMATIC);
|
||||
} else if (changes & BSS_CHANGED_BEACON_INFO) {
|
||||
/*
|
||||
* We received a beacon _after_ association so
|
||||
|
@ -1012,9 +1014,16 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
if (ret)
|
||||
goto out_unbind;
|
||||
|
||||
/* must be set before quota calculations */
|
||||
mvmvif->ap_ibss_active = true;
|
||||
|
||||
/* power updated needs to be done before quotas */
|
||||
mvm->bound_vif_cnt++;
|
||||
iwl_mvm_power_update_binding(mvm, vif, true);
|
||||
|
||||
ret = iwl_mvm_update_quotas(mvm, vif);
|
||||
if (ret)
|
||||
goto out_rm_bcast;
|
||||
goto out_quota_failed;
|
||||
|
||||
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
|
||||
if (vif->p2p && mvm->p2p_device_vif)
|
||||
|
@ -1025,7 +1034,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
mutex_unlock(&mvm->mutex);
|
||||
return 0;
|
||||
|
||||
out_rm_bcast:
|
||||
out_quota_failed:
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_binding(mvm, vif, false);
|
||||
mvmvif->ap_ibss_active = false;
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
||||
out_unbind:
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
|
@ -1057,6 +1069,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
|
|||
iwl_mvm_update_quotas(mvm, NULL);
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_binding(mvm, vif, false);
|
||||
|
||||
iwl_mvm_mac_ctxt_remove(mvm, vif);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
@ -1790,11 +1806,11 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
out_unlock:
|
||||
mvmvif->phy_ctxt = NULL;
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_binding(mvm, vif, false);
|
||||
|
||||
out_unlock:
|
||||
mvmvif->phy_ctxt = NULL;
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -392,17 +392,16 @@ out:
|
|||
/* Loads the NVM data stored in mvm->nvm_sections into the NIC */
|
||||
int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
|
||||
{
|
||||
int i, ret;
|
||||
u16 section_id;
|
||||
int i, ret = 0;
|
||||
struct iwl_nvm_section *sections = mvm->nvm_sections;
|
||||
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "'Write to NVM\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
|
||||
section_id = nvm_to_read[i];
|
||||
ret = iwl_nvm_write_section(mvm, section_id,
|
||||
sections[section_id].data,
|
||||
sections[section_id].length);
|
||||
for (i = 0; i < ARRAY_SIZE(mvm->nvm_sections); i++) {
|
||||
if (!mvm->nvm_sections[i].data || !mvm->nvm_sections[i].length)
|
||||
continue;
|
||||
ret = iwl_nvm_write_section(mvm, i, sections[i].data,
|
||||
sections[i].length);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
|
||||
break;
|
||||
|
|
|
@ -309,6 +309,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
|||
CMD(BT_PROFILE_NOTIFICATION),
|
||||
CMD(BT_CONFIG),
|
||||
CMD(MCAST_FILTER_CMD),
|
||||
CMD(REPLY_SF_CFG_CMD),
|
||||
CMD(REPLY_BEACON_FILTERING_CMD),
|
||||
CMD(REPLY_THERMAL_MNG_BACKOFF),
|
||||
CMD(MAC_PM_POWER_TABLE),
|
||||
|
@ -472,6 +473,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
out_unregister:
|
||||
ieee80211_unregister_hw(mvm->hw);
|
||||
iwl_mvm_leds_exit(mvm);
|
||||
out_free:
|
||||
iwl_phy_db_free(mvm->phy_db);
|
||||
kfree(mvm->scan_cmd);
|
||||
|
|
|
@ -356,7 +356,7 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
|
|||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return IWL_RATE_INVALID;
|
||||
}
|
||||
|
||||
static void rs_rate_scale_perform(struct iwl_mvm *mvm,
|
||||
|
@ -702,10 +702,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
|
|||
memset(rate, 0, sizeof(*rate));
|
||||
rate->index = iwl_hwrate_to_plcp_idx(ucode_rate);
|
||||
|
||||
if (rate->index == IWL_RATE_INVALID) {
|
||||
rate->index = -1;
|
||||
if (rate->index == IWL_RATE_INVALID)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate->ant = (ant_msk >> RATE_MCS_ANT_POS);
|
||||
|
||||
|
@ -1590,6 +1588,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
|
|||
search_tbl->column = col_id;
|
||||
rs_set_expected_tpt_table(lq_sta, search_tbl);
|
||||
|
||||
lq_sta->visited_columns |= BIT(col_id);
|
||||
|
||||
/* Get the best matching rate if we're changing modes. e.g.
|
||||
* SISO->MIMO, LEGACY->SISO, MIMO->SISO
|
||||
*/
|
||||
|
@ -1613,7 +1613,6 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
|
|||
IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n",
|
||||
col_id, rate->index);
|
||||
|
||||
lq_sta->visited_columns |= BIT(col_id);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -2560,7 +2559,9 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
|
|||
int index = iwl_hwrate_to_plcp_idx(rate);
|
||||
|
||||
return sprintf(buf, "Legacy | ANT: %s Rate: %s Mbps\n",
|
||||
rs_pretty_ant(ant), iwl_rate_mcs[index].mbps);
|
||||
rs_pretty_ant(ant),
|
||||
index == IWL_RATE_INVALID ? "BAD" :
|
||||
iwl_rate_mcs[index].mbps);
|
||||
}
|
||||
|
||||
if (rate & RATE_MCS_VHT_MSK) {
|
||||
|
|
|
@ -249,12 +249,12 @@ static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
|
|||
container_of(notif_wait, struct iwl_mvm, notif_wait);
|
||||
struct iwl_mvm_time_event_data *te_data = data;
|
||||
struct iwl_time_event_resp *resp;
|
||||
int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
int resp_len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
|
||||
return true;
|
||||
|
||||
if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
|
||||
if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
|
||||
IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -390,7 +390,6 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
seq_number &= IEEE80211_SCTL_SEQ;
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(seq_number);
|
||||
seq_number += 0x10;
|
||||
is_data_qos = true;
|
||||
is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
|
||||
}
|
||||
|
@ -407,13 +406,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
|
||||
tid, txq_id, seq_number);
|
||||
tid, txq_id, IEEE80211_SEQ_TO_SN(seq_number));
|
||||
|
||||
if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
|
||||
goto drop_unlock_sta;
|
||||
|
||||
if (is_data_qos && !ieee80211_has_morefrags(fc))
|
||||
mvmsta->tid_data[tid].seq_number = seq_number;
|
||||
mvmsta->tid_data[tid].seq_number = seq_number + 0x10;
|
||||
|
||||
spin_unlock(&mvmsta->lock);
|
||||
|
||||
|
@ -704,7 +703,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
*/
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta)) {
|
||||
if (!sta || PTR_ERR(sta) == -EBUSY) {
|
||||
/*
|
||||
* Station disappeared in the meantime:
|
||||
* so we are draining.
|
||||
|
@ -713,7 +712,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
schedule_work(&mvm->sta_drained_wk);
|
||||
}
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
} else if (!mvmsta) {
|
||||
} else if (!mvmsta && PTR_ERR(sta) == -EBUSY) {
|
||||
/* Tx response without STA, so we are draining */
|
||||
set_bit(sta_id, mvm->sta_drained);
|
||||
schedule_work(&mvm->sta_drained_wk);
|
||||
|
|
|
@ -168,8 +168,8 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
|
|||
goto out_free_resp;
|
||||
}
|
||||
|
||||
resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
|
||||
resp_len = iwl_rx_packet_payload_len(pkt);
|
||||
if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
|
||||
ret = -EIO;
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
|
|
@ -615,7 +615,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
|
|||
rxcb._offset, get_cmd_string(trans_pcie, pkt->hdr.cmd),
|
||||
pkt->hdr.cmd);
|
||||
|
||||
len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
len = iwl_rx_packet_len(pkt);
|
||||
len += sizeof(u32); /* account for status word */
|
||||
trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len);
|
||||
trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len);
|
||||
|
|
|
@ -178,6 +178,28 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (trans->cfg->host_interrupt_operation_mode) {
|
||||
/*
|
||||
* This is a bit of an abuse - This is needed for 7260 / 3160
|
||||
* only check host_interrupt_operation_mode even if this is
|
||||
* not related to host_interrupt_operation_mode.
|
||||
*
|
||||
* Enable the oscillator to count wake up time for L1 exit. This
|
||||
* consumes slightly more power (100uA) - but allows to be sure
|
||||
* that we wake up from L1 on time.
|
||||
*
|
||||
* This looks weird: read twice the same register, discard the
|
||||
* value, set a bit, and yet again, read that same register
|
||||
* just to discard the value. But that's the way the hardware
|
||||
* seems to like it.
|
||||
*/
|
||||
iwl_read_prph(trans, OSC_CLK);
|
||||
iwl_read_prph(trans, OSC_CLK);
|
||||
iwl_set_bits_prph(trans, OSC_CLK, OSC_CLK_FORCE_CONTROL);
|
||||
iwl_read_prph(trans, OSC_CLK);
|
||||
iwl_read_prph(trans, OSC_CLK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable DMA clock and wait for it to stabilize.
|
||||
*
|
||||
|
|
|
@ -1268,14 +1268,9 @@ static struct cfg80211_scan_request *
|
|||
_new_connect_scan_req(struct wiphy *wiphy, struct cfg80211_connect_params *sme)
|
||||
{
|
||||
struct cfg80211_scan_request *creq = NULL;
|
||||
int i, n_channels = 0;
|
||||
int i, n_channels = ieee80211_get_num_supported_channels(wiphy);
|
||||
enum ieee80211_band band;
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (wiphy->bands[band])
|
||||
n_channels += wiphy->bands[band]->n_channels;
|
||||
}
|
||||
|
||||
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
|
||||
n_channels * sizeof(void *),
|
||||
GFP_ATOMIC);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -65,6 +65,9 @@ enum hwsim_tx_control_flags {
|
|||
* kernel, uses:
|
||||
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
|
||||
* %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
|
||||
* @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters,
|
||||
* returns the radio ID (>= 0) or negative on errors
|
||||
* @HWSIM_CMD_DESTROY_RADIO: destroy a radio
|
||||
* @__HWSIM_CMD_MAX: enum limit
|
||||
*/
|
||||
enum {
|
||||
|
@ -72,6 +75,8 @@ enum {
|
|||
HWSIM_CMD_REGISTER,
|
||||
HWSIM_CMD_FRAME,
|
||||
HWSIM_CMD_TX_INFO_FRAME,
|
||||
HWSIM_CMD_CREATE_RADIO,
|
||||
HWSIM_CMD_DESTROY_RADIO,
|
||||
__HWSIM_CMD_MAX,
|
||||
};
|
||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||
|
@ -94,6 +99,14 @@ enum {
|
|||
space
|
||||
* @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array
|
||||
* @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame
|
||||
* @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO
|
||||
* command giving the number of channels supported by the new radio
|
||||
* @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO
|
||||
* only to destroy a radio
|
||||
* @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint
|
||||
* (nla string, length 2)
|
||||
* @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
|
||||
* @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
|
||||
* @__HWSIM_ATTR_MAX: enum limit
|
||||
*/
|
||||
|
||||
|
@ -108,6 +121,11 @@ enum {
|
|||
HWSIM_ATTR_SIGNAL,
|
||||
HWSIM_ATTR_TX_INFO,
|
||||
HWSIM_ATTR_COOKIE,
|
||||
HWSIM_ATTR_CHANNELS,
|
||||
HWSIM_ATTR_RADIO_ID,
|
||||
HWSIM_ATTR_REG_HINT_ALPHA2,
|
||||
HWSIM_ATTR_REG_CUSTOM_REG,
|
||||
HWSIM_ATTR_REG_STRICT_REG,
|
||||
__HWSIM_ATTR_MAX,
|
||||
};
|
||||
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
||||
|
|
|
@ -31,12 +31,12 @@ config MWIFIEX_PCIE
|
|||
mwifiex_pcie.
|
||||
|
||||
config MWIFIEX_USB
|
||||
tristate "Marvell WiFi-Ex Driver for USB8797"
|
||||
tristate "Marvell WiFi-Ex Driver for USB8797/8897"
|
||||
depends on MWIFIEX && USB
|
||||
select FW_LOADER
|
||||
---help---
|
||||
This adds support for wireless adapters based on Marvell
|
||||
Avastar 88W8797 chipset with USB interface.
|
||||
8797/8897 chipset with USB interface.
|
||||
|
||||
If you choose to build it as a module, it will be called
|
||||
mwifiex_usb.
|
||||
|
|
|
@ -2677,6 +2677,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
struct wiphy *wiphy;
|
||||
struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
|
||||
u8 *country_code;
|
||||
u32 thr, retry;
|
||||
|
||||
/* create a new wiphy for use with cfg80211 */
|
||||
wiphy = wiphy_new(&mwifiex_cfg80211_ops,
|
||||
|
@ -2766,6 +2767,19 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
country_code);
|
||||
}
|
||||
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr);
|
||||
wiphy->frag_threshold = thr;
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr);
|
||||
wiphy->rts_threshold = thr;
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry);
|
||||
wiphy->retry_short = (u8) retry;
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry);
|
||||
wiphy->retry_long = (u8) retry;
|
||||
|
||||
adapter->wiphy = wiphy;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
|||
|
||||
/* HW_SPEC fw_cap_info */
|
||||
|
||||
#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
|
||||
#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(12)|BIT(13)))
|
||||
|
||||
#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
|
||||
#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
|
||||
|
|
|
@ -1681,7 +1681,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
const u8 *ie_buf;
|
||||
size_t ie_len;
|
||||
u16 channel = 0;
|
||||
u64 fw_tsf = 0;
|
||||
__le64 fw_tsf = 0;
|
||||
u16 beacon_size = 0;
|
||||
u32 curr_bcn_bytes;
|
||||
u32 freq;
|
||||
|
@ -1815,7 +1815,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
ie_buf, ie_len, rssi, GFP_KERNEL);
|
||||
bss_priv = (struct mwifiex_bss_priv *)bss->priv;
|
||||
bss_priv->band = band;
|
||||
bss_priv->fw_tsf = fw_tsf;
|
||||
bss_priv->fw_tsf = le64_to_cpu(fw_tsf);
|
||||
if (priv->media_connected &&
|
||||
!memcmp(bssid,
|
||||
priv->curr_bss_params.bss_descriptor
|
||||
|
|
|
@ -22,15 +22,21 @@
|
|||
|
||||
#define USB_VERSION "1.0"
|
||||
|
||||
static const char usbdriver_name[] = "usb8797";
|
||||
static const char usbdriver_name[] = "usb8xxx";
|
||||
|
||||
static struct mwifiex_if_ops usb_ops;
|
||||
static struct semaphore add_remove_card_sem;
|
||||
static struct usb_card_rec *usb_card;
|
||||
|
||||
static struct usb_device_id mwifiex_usb_table[] = {
|
||||
{USB_DEVICE(USB8797_VID, USB8797_PID_1)},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(USB8797_VID, USB8797_PID_2,
|
||||
/* 8797 */
|
||||
{USB_DEVICE(USB8XXX_VID, USB8797_PID_1)},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2,
|
||||
USB_CLASS_VENDOR_SPEC,
|
||||
USB_SUBCLASS_VENDOR_SPEC, 0xff)},
|
||||
/* 8897 */
|
||||
{USB_DEVICE(USB8XXX_VID, USB8897_PID_1)},
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2,
|
||||
USB_CLASS_VENDOR_SPEC,
|
||||
USB_SUBCLASS_VENDOR_SPEC, 0xff)},
|
||||
{ } /* Terminating entry */
|
||||
|
@ -343,10 +349,20 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
|
|||
id_vendor, id_product, bcd_device);
|
||||
|
||||
/* PID_1 is used for firmware downloading only */
|
||||
if (id_product == USB8797_PID_1)
|
||||
card->usb_boot_state = USB8797_FW_DNLD;
|
||||
else
|
||||
card->usb_boot_state = USB8797_FW_READY;
|
||||
switch (id_product) {
|
||||
case USB8797_PID_1:
|
||||
case USB8897_PID_1:
|
||||
card->usb_boot_state = USB8XXX_FW_DNLD;
|
||||
break;
|
||||
case USB8797_PID_2:
|
||||
case USB8897_PID_2:
|
||||
card->usb_boot_state = USB8XXX_FW_READY;
|
||||
break;
|
||||
default:
|
||||
pr_warning("unknown id_product %#x\n", id_product);
|
||||
card->usb_boot_state = USB8XXX_FW_DNLD;
|
||||
break;
|
||||
}
|
||||
|
||||
card->udev = udev;
|
||||
card->intf = intf;
|
||||
|
@ -755,9 +771,20 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
|
|||
|
||||
card->adapter = adapter;
|
||||
adapter->dev = &card->udev->dev;
|
||||
strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME);
|
||||
usb_card = card;
|
||||
|
||||
switch (le16_to_cpu(card->udev->descriptor.idProduct)) {
|
||||
case USB8897_PID_1:
|
||||
case USB8897_PID_2:
|
||||
strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
|
||||
break;
|
||||
case USB8797_PID_1:
|
||||
case USB8797_PID_2:
|
||||
default:
|
||||
strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -773,7 +800,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
|
|||
{
|
||||
int ret = 0;
|
||||
u8 *firmware = fw->fw_buf, *recv_buff;
|
||||
u32 retries = USB8797_FW_MAX_RETRY, dlen;
|
||||
u32 retries = USB8XXX_FW_MAX_RETRY, dlen;
|
||||
u32 fw_seqnum = 0, tlen = 0, dnld_cmd = 0;
|
||||
struct fw_data *fwdata;
|
||||
struct fw_sync_header sync_fw;
|
||||
|
@ -875,7 +902,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
|
|||
continue;
|
||||
}
|
||||
|
||||
retries = USB8797_FW_MAX_RETRY;
|
||||
retries = USB8XXX_FW_MAX_RETRY;
|
||||
break;
|
||||
}
|
||||
fw_seqnum++;
|
||||
|
@ -899,13 +926,13 @@ static int mwifiex_usb_dnld_fw(struct mwifiex_adapter *adapter,
|
|||
int ret;
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
|
||||
if (card->usb_boot_state == USB8797_FW_DNLD) {
|
||||
if (card->usb_boot_state == USB8XXX_FW_DNLD) {
|
||||
ret = mwifiex_prog_fw_w_helper(adapter, fw);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
/* Boot state changes after successful firmware download */
|
||||
if (card->usb_boot_state == USB8797_FW_DNLD)
|
||||
if (card->usb_boot_state == USB8XXX_FW_DNLD)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1039,4 +1066,5 @@ MODULE_AUTHOR("Marvell International Ltd.");
|
|||
MODULE_DESCRIPTION("Marvell WiFi-Ex USB Driver version" USB_VERSION);
|
||||
MODULE_VERSION(USB_VERSION);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_FIRMWARE("mrvl/usb8797_uapsta.bin");
|
||||
MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME);
|
||||
MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME);
|
||||
|
|
|
@ -22,19 +22,23 @@
|
|||
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define USB8797_VID 0x1286
|
||||
#define USB8XXX_VID 0x1286
|
||||
|
||||
#define USB8797_PID_1 0x2043
|
||||
#define USB8797_PID_2 0x2044
|
||||
#define USB8897_PID_1 0x2045
|
||||
#define USB8897_PID_2 0x2046
|
||||
|
||||
#define USB8797_FW_DNLD 1
|
||||
#define USB8797_FW_READY 2
|
||||
#define USB8797_FW_MAX_RETRY 3
|
||||
#define USB8XXX_FW_DNLD 1
|
||||
#define USB8XXX_FW_READY 2
|
||||
#define USB8XXX_FW_MAX_RETRY 3
|
||||
|
||||
#define MWIFIEX_TX_DATA_URB 6
|
||||
#define MWIFIEX_RX_DATA_URB 6
|
||||
#define MWIFIEX_USB_TIMEOUT 100
|
||||
|
||||
#define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin"
|
||||
#define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin"
|
||||
|
||||
#define FW_DNLD_TX_BUF_SIZE 620
|
||||
#define FW_DNLD_RX_BUF_SIZE 2048
|
||||
|
|
|
@ -5892,8 +5892,6 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
|
|||
|
||||
hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0;
|
||||
|
||||
hw->channel_change_time = 10;
|
||||
|
||||
hw->queues = MWL8K_TX_WMM_QUEUES;
|
||||
|
||||
/* Set rssi values to dBm */
|
||||
|
|
|
@ -756,7 +756,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
dev->channel_change_time = 1000; /* TODO: find actual value */
|
||||
priv->beacon_req_id = cpu_to_le32(0);
|
||||
priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
|
||||
priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
|
||||
|
|
|
@ -586,7 +586,7 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
|
|||
chan = priv->curchan;
|
||||
if (chan) {
|
||||
struct survey_info *survey = &priv->survey[chan->hw_value];
|
||||
survey->noise = clamp_t(s8, priv->noise, -128, 127);
|
||||
survey->noise = clamp(priv->noise, -128, 127);
|
||||
survey->channel_time = priv->survey_raw.active;
|
||||
survey->channel_time_tx = priv->survey_raw.tx;
|
||||
survey->channel_time_busy = priv->survey_raw.tx +
|
||||
|
|
|
@ -353,7 +353,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
|
|||
|
||||
/* TODO: Correct this value for our hw */
|
||||
/* TODO: define these hard code value */
|
||||
hw->channel_change_time = 100;
|
||||
hw->max_listen_interval = 10;
|
||||
hw->max_rate_tries = 4;
|
||||
/* hw->max_rates = 1; */
|
||||
|
|
|
@ -317,6 +317,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
|
|||
{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
|
||||
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
|
||||
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
|
||||
{RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/
|
||||
{RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
|
||||
{RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
|
||||
/* HP - Lite-On ,8188CUS Slim Combo */
|
||||
|
|
|
@ -1468,7 +1468,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
|
|||
|
||||
/* unit us */
|
||||
/* FIXME: find a proper value */
|
||||
wl->hw->channel_change_time = 10000;
|
||||
|
||||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
|
|
|
@ -4457,6 +4457,16 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if ((changed & BSS_CHANGED_TXPOWER) &&
|
||||
bss_conf->txpower != wlvif->power_level) {
|
||||
|
||||
ret = wl1271_acx_tx_power(wl, wlvif, bss_conf->txpower);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wlvif->power_level = bss_conf->txpower;
|
||||
}
|
||||
|
||||
if (is_ap)
|
||||
wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
|
||||
else
|
||||
|
@ -5710,7 +5720,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
|||
|
||||
/* unit us */
|
||||
/* FIXME: find a proper value */
|
||||
wl->hw->channel_change_time = 10000;
|
||||
wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
|
||||
|
||||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
|
|
|
@ -58,5 +58,6 @@ config NFC_PORT100
|
|||
|
||||
source "drivers/nfc/pn544/Kconfig"
|
||||
source "drivers/nfc/microread/Kconfig"
|
||||
source "drivers/nfc/nfcmrvl/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -9,5 +9,6 @@ obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
|||
obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
|
||||
obj-$(CONFIG_NFC_SIM) += nfcsim.o
|
||||
obj-$(CONFIG_NFC_PORT100) += port100.o
|
||||
obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
|
||||
|
||||
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
|
||||
|
|
|
@ -127,7 +127,7 @@ void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
|
|||
|
||||
reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
|
||||
if (reply_size < MEI_NFC_HEADER_SIZE) {
|
||||
kfree(skb);
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
config NFC_MRVL
|
||||
tristate "Marvell NFC driver support"
|
||||
depends on NFC_NCI
|
||||
help
|
||||
The core driver to support Marvell NFC devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell NFC device 8897.
|
||||
|
||||
Say Y here to compile Marvell NFC driver into the kernel or
|
||||
say M to compile it as module.
|
||||
|
||||
config NFC_MRVL_USB
|
||||
tristate "Marvell NFC-over-USB driver"
|
||||
depends on NFC_MRVL && USB
|
||||
help
|
||||
Marvell NFC-over-USB driver.
|
||||
|
||||
This driver provides support for Marvell NFC-over-USB devices:
|
||||
8897.
|
||||
|
||||
Say Y here to compile support for Marvell NFC-over-USB driver
|
||||
into the kernel or say M to compile it as module.
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for NFCMRVL NCI based NFC driver
|
||||
#
|
||||
|
||||
nfcmrvl-y += main.o
|
||||
obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
|
||||
|
||||
nfcmrvl_usb-y += usb.o
|
||||
obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Marvell NFC driver: major functions
|
||||
*
|
||||
* Copyright (C) 2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available on the worldwide web at
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nci.h>
|
||||
#include <net/nfc/nci_core.h>
|
||||
#include "nfcmrvl.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
|
||||
static int nfcmrvl_nci_open(struct nci_dev *ndev)
|
||||
{
|
||||
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
|
||||
int err;
|
||||
|
||||
if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
|
||||
return 0;
|
||||
|
||||
err = priv->if_ops->nci_open(priv);
|
||||
|
||||
if (err)
|
||||
clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nfcmrvl_nci_close(struct nci_dev *ndev)
|
||||
{
|
||||
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
|
||||
|
||||
if (!test_and_clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
|
||||
return 0;
|
||||
|
||||
priv->if_ops->nci_close(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
{
|
||||
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
|
||||
|
||||
nfc_info(priv->dev, "send entry, len %d\n", skb->len);
|
||||
|
||||
skb->dev = (void *)ndev;
|
||||
|
||||
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
|
||||
return -EBUSY;
|
||||
|
||||
return priv->if_ops->nci_send(priv, skb);
|
||||
}
|
||||
|
||||
static int nfcmrvl_nci_setup(struct nci_dev *ndev)
|
||||
{
|
||||
__u8 val;
|
||||
|
||||
val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
|
||||
nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
|
||||
val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
|
||||
nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
|
||||
val = NFCMRVL_EXT_COEX_ENABLE;
|
||||
nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nci_ops nfcmrvl_nci_ops = {
|
||||
.open = nfcmrvl_nci_open,
|
||||
.close = nfcmrvl_nci_close,
|
||||
.send = nfcmrvl_nci_send,
|
||||
.setup = nfcmrvl_nci_setup,
|
||||
};
|
||||
|
||||
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
|
||||
struct nfcmrvl_if_ops *ops,
|
||||
struct device *dev)
|
||||
{
|
||||
struct nfcmrvl_private *priv;
|
||||
int rc;
|
||||
u32 protocols;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
priv->drv_data = drv_data;
|
||||
priv->if_ops = ops;
|
||||
priv->dev = dev;
|
||||
|
||||
protocols = NFC_PROTO_JEWEL_MASK
|
||||
| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
|
||||
| NFC_PROTO_ISO14443_MASK
|
||||
| NFC_PROTO_ISO14443_B_MASK
|
||||
| NFC_PROTO_NFC_DEP_MASK;
|
||||
|
||||
priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
|
||||
if (!priv->ndev) {
|
||||
nfc_err(dev, "nci_allocate_device failed");
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nci_set_drvdata(priv->ndev, priv);
|
||||
|
||||
rc = nci_register_device(priv->ndev);
|
||||
if (rc) {
|
||||
nfc_err(dev, "nci_register_device failed %d", rc);
|
||||
nci_free_device(priv->ndev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
nfc_info(dev, "registered with nci successfully\n");
|
||||
return priv;
|
||||
|
||||
error:
|
||||
kfree(priv);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfcmrvl_nci_register_dev);
|
||||
|
||||
void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
|
||||
{
|
||||
struct nci_dev *ndev = priv->ndev;
|
||||
|
||||
nci_unregister_device(ndev);
|
||||
nci_free_device(ndev);
|
||||
kfree(priv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
|
||||
|
||||
int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(skb_put(skb, count), data, count);
|
||||
nci_recv_frame(priv->ndev, skb);
|
||||
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
|
||||
|
||||
MODULE_AUTHOR("Marvell International Ltd.");
|
||||
MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Marvell NFC driver
|
||||
*
|
||||
* Copyright (C) 2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available on the worldwide web at
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
**/
|
||||
|
||||
/* Define private flags: */
|
||||
#define NFCMRVL_NCI_RUNNING 1
|
||||
|
||||
#define NFCMRVL_EXT_COEX_ID 0xE0
|
||||
#define NFCMRVL_NOT_ALLOWED_ID 0xE1
|
||||
#define NFCMRVL_ACTIVE_ID 0xE2
|
||||
#define NFCMRVL_EXT_COEX_ENABLE 1
|
||||
#define NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED 0xA
|
||||
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
|
||||
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
|
||||
|
||||
struct nfcmrvl_private {
|
||||
struct nci_dev *ndev;
|
||||
unsigned long flags;
|
||||
void *drv_data;
|
||||
struct device *dev;
|
||||
struct nfcmrvl_if_ops *if_ops;
|
||||
};
|
||||
|
||||
struct nfcmrvl_if_ops {
|
||||
int (*nci_open) (struct nfcmrvl_private *priv);
|
||||
int (*nci_close) (struct nfcmrvl_private *priv);
|
||||
int (*nci_send) (struct nfcmrvl_private *priv, struct sk_buff *skb);
|
||||
};
|
||||
|
||||
void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
|
||||
int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
|
||||
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
|
||||
struct nfcmrvl_if_ops *ops,
|
||||
struct device *dev);
|
|
@ -0,0 +1,459 @@
|
|||
/**
|
||||
* Marvell NFC-over-USB driver: USB interface related functions
|
||||
*
|
||||
* Copyright (C) 2014, Marvell International Ltd.
|
||||
*
|
||||
* This software file (the "File") is distributed by Marvell International
|
||||
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
||||
* (the "License"). You may use, redistribute and/or modify this File in
|
||||
* accordance with the terms and conditions of the License, a copy of which
|
||||
* is available on the worldwide web at
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*
|
||||
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
||||
* this warranty disclaimer.
|
||||
**/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nci.h>
|
||||
#include <net/nfc/nci_core.h>
|
||||
#include "nfcmrvl.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
|
||||
static struct usb_device_id nfcmrvl_table[] = {
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, nfcmrvl_table);
|
||||
|
||||
#define NFCMRVL_USB_BULK_RUNNING 1
|
||||
#define NFCMRVL_USB_SUSPENDING 2
|
||||
|
||||
struct nfcmrvl_usb_drv_data {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
unsigned long flags;
|
||||
struct work_struct waker;
|
||||
struct usb_anchor tx_anchor;
|
||||
struct usb_anchor bulk_anchor;
|
||||
struct usb_anchor deferred;
|
||||
int tx_in_flight;
|
||||
/* protects tx_in_flight */
|
||||
spinlock_t txlock;
|
||||
struct usb_endpoint_descriptor *bulk_tx_ep;
|
||||
struct usb_endpoint_descriptor *bulk_rx_ep;
|
||||
int suspend_count;
|
||||
struct nfcmrvl_private *priv;
|
||||
};
|
||||
|
||||
static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&drv_data->txlock, flags);
|
||||
rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
|
||||
if (!rv)
|
||||
drv_data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&drv_data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void nfcmrvl_bulk_complete(struct urb *urb)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = urb->context;
|
||||
int err;
|
||||
|
||||
dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
|
||||
return;
|
||||
|
||||
if (!urb->status) {
|
||||
if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
|
||||
urb->actual_length) < 0)
|
||||
nfc_err(&drv_data->udev->dev, "corrupted Rx packet");
|
||||
}
|
||||
|
||||
if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
|
||||
return;
|
||||
|
||||
usb_anchor_urb(urb, &drv_data->bulk_anchor);
|
||||
usb_mark_last_busy(drv_data->udev);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err) {
|
||||
/* -EPERM: urb is being killed;
|
||||
* -ENODEV: device got disconnected
|
||||
*/
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
nfc_err(&drv_data->udev->dev,
|
||||
"urb %p failed to resubmit (%d)", urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
|
||||
{
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE;
|
||||
|
||||
if (!drv_data->bulk_rx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
urb = usb_alloc_urb(0, mem_flags);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = kmalloc(size, mem_flags);
|
||||
if (!buf) {
|
||||
usb_free_urb(urb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pipe = usb_rcvbulkpipe(drv_data->udev,
|
||||
drv_data->bulk_rx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
|
||||
nfcmrvl_bulk_complete, drv_data);
|
||||
|
||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||
|
||||
usb_mark_last_busy(drv_data->udev);
|
||||
usb_anchor_urb(urb, &drv_data->bulk_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, mem_flags);
|
||||
if (err) {
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
nfc_err(&drv_data->udev->dev,
|
||||
"urb %p submission failed (%d)", urb, -err);
|
||||
usb_unanchor_urb(urb);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nfcmrvl_tx_complete(struct urb *urb)
|
||||
{
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct nci_dev *ndev = (struct nci_dev *)skb->dev;
|
||||
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
|
||||
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
|
||||
|
||||
nfc_info(priv->dev, "urb %p status %d count %d",
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
spin_lock(&drv_data->txlock);
|
||||
drv_data->tx_in_flight--;
|
||||
spin_unlock(&drv_data->txlock);
|
||||
|
||||
kfree(urb->setup_packet);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
|
||||
int err;
|
||||
|
||||
err = usb_autopm_get_interface(drv_data->intf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
drv_data->intf->needs_remote_wakeup = 1;
|
||||
|
||||
err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
|
||||
if (err)
|
||||
goto failed;
|
||||
|
||||
set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
|
||||
nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
|
||||
|
||||
usb_autopm_put_interface(drv_data->intf);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
usb_autopm_put_interface(drv_data->intf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data)
|
||||
{
|
||||
usb_kill_anchored_urbs(&drv_data->bulk_anchor);
|
||||
}
|
||||
|
||||
static int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
|
||||
int err;
|
||||
|
||||
cancel_work_sync(&drv_data->waker);
|
||||
|
||||
clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
|
||||
|
||||
nfcmrvl_usb_stop_traffic(drv_data);
|
||||
usb_kill_anchored_urbs(&drv_data->tx_anchor);
|
||||
err = usb_autopm_get_interface(drv_data->intf);
|
||||
if (err)
|
||||
goto failed;
|
||||
|
||||
drv_data->intf->needs_remote_wakeup = 0;
|
||||
usb_autopm_put_interface(drv_data->intf);
|
||||
|
||||
failed:
|
||||
usb_scuttle_anchored_urbs(&drv_data->deferred);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
int err;
|
||||
|
||||
if (!drv_data->bulk_tx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
pipe = usb_sndbulkpipe(drv_data->udev,
|
||||
drv_data->bulk_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len,
|
||||
nfcmrvl_tx_complete, skb);
|
||||
|
||||
err = nfcmrvl_inc_tx(drv_data);
|
||||
if (err) {
|
||||
usb_anchor_urb(urb, &drv_data->deferred);
|
||||
schedule_work(&drv_data->waker);
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
usb_anchor_urb(urb, &drv_data->tx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err) {
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
nfc_err(&drv_data->udev->dev,
|
||||
"urb %p submission failed (%d)", urb, -err);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
} else {
|
||||
usb_mark_last_busy(drv_data->udev);
|
||||
}
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct nfcmrvl_if_ops usb_ops = {
|
||||
.nci_open = nfcmrvl_usb_nci_open,
|
||||
.nci_close = nfcmrvl_usb_nci_close,
|
||||
.nci_send = nfcmrvl_usb_nci_send,
|
||||
};
|
||||
|
||||
static void nfcmrvl_waker(struct work_struct *work)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data =
|
||||
container_of(work, struct nfcmrvl_usb_drv_data, waker);
|
||||
int err;
|
||||
|
||||
err = usb_autopm_get_interface(drv_data->intf);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
usb_autopm_put_interface(drv_data->intf);
|
||||
}
|
||||
|
||||
static int nfcmrvl_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
struct nfcmrvl_usb_drv_data *drv_data;
|
||||
struct nfcmrvl_private *priv;
|
||||
int i;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
nfc_info(&udev->dev, "intf %p id %p", intf, id);
|
||||
|
||||
drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
|
||||
ep_desc = &intf->cur_altsetting->endpoint[i].desc;
|
||||
|
||||
if (!drv_data->bulk_tx_ep &&
|
||||
usb_endpoint_is_bulk_out(ep_desc)) {
|
||||
drv_data->bulk_tx_ep = ep_desc;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!drv_data->bulk_rx_ep &&
|
||||
usb_endpoint_is_bulk_in(ep_desc)) {
|
||||
drv_data->bulk_rx_ep = ep_desc;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
drv_data->udev = udev;
|
||||
drv_data->intf = intf;
|
||||
|
||||
INIT_WORK(&drv_data->waker, nfcmrvl_waker);
|
||||
spin_lock_init(&drv_data->txlock);
|
||||
|
||||
init_usb_anchor(&drv_data->tx_anchor);
|
||||
init_usb_anchor(&drv_data->bulk_anchor);
|
||||
init_usb_anchor(&drv_data->deferred);
|
||||
|
||||
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
|
||||
&drv_data->udev->dev);
|
||||
if (IS_ERR(priv))
|
||||
return PTR_ERR(priv);
|
||||
|
||||
drv_data->priv = priv;
|
||||
priv->dev = &drv_data->udev->dev;
|
||||
|
||||
usb_set_intfdata(intf, drv_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfcmrvl_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
|
||||
|
||||
if (!drv_data)
|
||||
return;
|
||||
|
||||
nfc_info(&drv_data->udev->dev, "intf %p", intf);
|
||||
|
||||
nfcmrvl_nci_unregister_dev(drv_data->priv);
|
||||
|
||||
usb_set_intfdata(drv_data->intf, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
|
||||
|
||||
nfc_info(&drv_data->udev->dev, "intf %p", intf);
|
||||
|
||||
if (drv_data->suspend_count++)
|
||||
return 0;
|
||||
|
||||
spin_lock_irq(&drv_data->txlock);
|
||||
if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) {
|
||||
set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
|
||||
spin_unlock_irq(&drv_data->txlock);
|
||||
} else {
|
||||
spin_unlock_irq(&drv_data->txlock);
|
||||
drv_data->suspend_count--;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
nfcmrvl_usb_stop_traffic(drv_data);
|
||||
usb_kill_anchored_urbs(&drv_data->tx_anchor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
|
||||
{
|
||||
struct urb *urb;
|
||||
int err;
|
||||
|
||||
while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
drv_data->tx_in_flight++;
|
||||
}
|
||||
usb_scuttle_anchored_urbs(&drv_data->deferred);
|
||||
}
|
||||
|
||||
static int nfcmrvl_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
|
||||
int err = 0;
|
||||
|
||||
nfc_info(&drv_data->udev->dev, "intf %p", intf);
|
||||
|
||||
if (--drv_data->suspend_count)
|
||||
return 0;
|
||||
|
||||
if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
|
||||
goto done;
|
||||
|
||||
if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
|
||||
err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
|
||||
if (err) {
|
||||
clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
|
||||
}
|
||||
|
||||
spin_lock_irq(&drv_data->txlock);
|
||||
nfcmrvl_play_deferred(drv_data);
|
||||
clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
|
||||
spin_unlock_irq(&drv_data->txlock);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
usb_scuttle_anchored_urbs(&drv_data->deferred);
|
||||
done:
|
||||
spin_lock_irq(&drv_data->txlock);
|
||||
clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
|
||||
spin_unlock_irq(&drv_data->txlock);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct usb_driver nfcmrvl_usb_driver = {
|
||||
.name = "nfcmrvl",
|
||||
.probe = nfcmrvl_probe,
|
||||
.disconnect = nfcmrvl_disconnect,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = nfcmrvl_suspend,
|
||||
.resume = nfcmrvl_resume,
|
||||
.reset_resume = nfcmrvl_resume,
|
||||
#endif
|
||||
.id_table = nfcmrvl_table,
|
||||
.supports_autosuspend = 1,
|
||||
.disable_hub_initiated_lpm = 1,
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
module_usb_driver(nfcmrvl_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Marvell International Ltd.");
|
||||
MODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -521,6 +521,9 @@ static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
|
|||
if (frame->ccid.type != 0x83)
|
||||
return false;
|
||||
|
||||
if (!frame->ccid.datalen)
|
||||
return false;
|
||||
|
||||
if (frame->data[frame->ccid.datalen - 2] == 0x63)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -195,42 +195,42 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
|
|||
|
||||
{{0x9e, 0xaa}, 0x01},
|
||||
|
||||
{{0x9b, 0xd1}, 0x0d},
|
||||
{{0x9b, 0xd2}, 0x24},
|
||||
{{0x9b, 0xd3}, 0x0a},
|
||||
{{0x9b, 0xd4}, 0x22},
|
||||
{{0x9b, 0xd5}, 0x08},
|
||||
{{0x9b, 0xd6}, 0x1e},
|
||||
{{0x9b, 0xdd}, 0x1c},
|
||||
{{0x9b, 0xd1}, 0x17},
|
||||
{{0x9b, 0xd2}, 0x58},
|
||||
{{0x9b, 0xd3}, 0x10},
|
||||
{{0x9b, 0xd4}, 0x47},
|
||||
{{0x9b, 0xd5}, 0x0c},
|
||||
{{0x9b, 0xd6}, 0x37},
|
||||
{{0x9b, 0xdd}, 0x33},
|
||||
|
||||
{{0x9b, 0x84}, 0x13},
|
||||
{{0x99, 0x81}, 0x7f},
|
||||
{{0x99, 0x31}, 0x70},
|
||||
{{0x9b, 0x84}, 0x00},
|
||||
{{0x99, 0x81}, 0x79},
|
||||
{{0x99, 0x31}, 0x79},
|
||||
|
||||
{{0x98, 0x00}, 0x3f},
|
||||
|
||||
{{0x9f, 0x09}, 0x00},
|
||||
{{0x9f, 0x09}, 0x02},
|
||||
|
||||
{{0x9f, 0x0a}, 0x05},
|
||||
|
||||
{{0x9e, 0xd1}, 0xa1},
|
||||
{{0x99, 0x23}, 0x00},
|
||||
|
||||
{{0x9e, 0x74}, 0x80},
|
||||
{{0x99, 0x23}, 0x01},
|
||||
|
||||
{{0x9e, 0x74}, 0x00},
|
||||
{{0x9e, 0x90}, 0x00},
|
||||
{{0x9f, 0x28}, 0x10},
|
||||
|
||||
{{0x9f, 0x35}, 0x14},
|
||||
{{0x9f, 0x35}, 0x04},
|
||||
|
||||
{{0x9f, 0x36}, 0x60},
|
||||
{{0x9f, 0x36}, 0x11},
|
||||
|
||||
{{0x9c, 0x31}, 0x00},
|
||||
|
||||
{{0x9c, 0x32}, 0xc8},
|
||||
{{0x9c, 0x32}, 0x00},
|
||||
|
||||
{{0x9c, 0x19}, 0x40},
|
||||
{{0x9c, 0x19}, 0x0a},
|
||||
|
||||
{{0x9c, 0x1a}, 0x40},
|
||||
{{0x9c, 0x1a}, 0x0a},
|
||||
|
||||
{{0x9c, 0x0c}, 0x00},
|
||||
|
||||
|
@ -240,13 +240,13 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
|
|||
|
||||
{{0x9c, 0x13}, 0x00},
|
||||
|
||||
{{0x98, 0xa2}, 0x0e},
|
||||
{{0x98, 0xa2}, 0x09},
|
||||
|
||||
{{0x98, 0x93}, 0x40},
|
||||
{{0x98, 0x93}, 0x00},
|
||||
|
||||
{{0x98, 0x7d}, 0x02},
|
||||
{{0x98, 0x7d}, 0x08},
|
||||
{{0x98, 0x7e}, 0x00},
|
||||
{{0x9f, 0xc8}, 0x01},
|
||||
{{0x9f, 0xc8}, 0x00},
|
||||
};
|
||||
struct hw_config *p = hw_config;
|
||||
int count = ARRAY_SIZE(hw_config);
|
||||
|
|
|
@ -1509,6 +1509,7 @@ static void port100_disconnect(struct usb_interface *interface)
|
|||
|
||||
usb_free_urb(dev->in_urb);
|
||||
usb_free_urb(dev->out_urb);
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
kfree(dev->cmd);
|
||||
|
||||
|
|
|
@ -788,7 +788,6 @@ static int wb35_probe(struct usb_interface *intf,
|
|||
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
dev->channel_change_time = 1000;
|
||||
dev->max_signal = 100;
|
||||
dev->queues = 1;
|
||||
|
||||
|
|
|
@ -1857,6 +1857,7 @@ enum ieee80211_key_len {
|
|||
WLAN_KEY_LEN_CCMP = 16,
|
||||
WLAN_KEY_LEN_TKIP = 32,
|
||||
WLAN_KEY_LEN_AES_CMAC = 16,
|
||||
WLAN_KEY_LEN_SMS4 = 32,
|
||||
};
|
||||
|
||||
#define IEEE80211_WEP_IV_LEN 4
|
||||
|
@ -1902,6 +1903,7 @@ enum ieee80211_tdls_actioncode {
|
|||
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
|
||||
|
||||
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
||||
#define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(7)
|
||||
|
||||
/* TDLS specific payload type in the LLC/SNAP header */
|
||||
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||
|
|
|
@ -4640,6 +4640,14 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
|
|||
*/
|
||||
void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* ieee80211_get_num_supported_channels - get number of channels device has
|
||||
* @wiphy: the wiphy
|
||||
*
|
||||
* Return: the number of channels supported by the device.
|
||||
*/
|
||||
unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
|
||||
|
||||
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
||||
|
||||
/* wiphy_printk helpers, similar to dev_printk */
|
||||
|
|
|
@ -1616,8 +1616,6 @@ enum ieee80211_hw_flags {
|
|||
* @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
|
||||
* Can be used by drivers to add extra IEs.
|
||||
*
|
||||
* @channel_change_time: time (in microseconds) it takes to change channels.
|
||||
*
|
||||
* @max_signal: Maximum value for signal (rssi) in RX information, used
|
||||
* only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
|
||||
*
|
||||
|
@ -1699,7 +1697,6 @@ struct ieee80211_hw {
|
|||
u32 flags;
|
||||
unsigned int extra_tx_headroom;
|
||||
unsigned int extra_beacon_tailroom;
|
||||
int channel_change_time;
|
||||
int vif_data_size;
|
||||
int sta_data_size;
|
||||
int chanctx_data_size;
|
||||
|
@ -2122,6 +2119,11 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
|||
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
|
||||
* and also take care of the EOSP and MORE_DATA bits in the frame.
|
||||
* The driver may also use ieee80211_sta_eosp() in this case.
|
||||
*
|
||||
* Note that if the driver ever buffers frames other than QoS-data
|
||||
* frames, it must take care to never send a non-QoS-data frame as
|
||||
* the last frame in a service period, adding a QoS-nulldata frame
|
||||
* after a non-QoS-data frame if needed.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -122,6 +122,16 @@ typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev,
|
|||
* switch_rf to turn the radio on. A call to in|tg_configure_hw must turn
|
||||
* the device radio on.
|
||||
* @abort_cmd: Discard the last sent command.
|
||||
*
|
||||
* Notes: Asynchronous functions have a timeout parameter. It is the driver
|
||||
* responsibility to call the digital stack back through the
|
||||
* nfc_digital_cmd_complete_t callback when no RF respsonse has been
|
||||
* received within the specified time (in milliseconds). In that case the
|
||||
* driver must set the resp sk_buff to ERR_PTR(-ETIMEDOUT).
|
||||
* Since the digital stack serializes commands to be sent, it's mandatory
|
||||
* for the driver to handle the timeout correctly. Otherwise the stack
|
||||
* would not be able to send new commands, waiting for the reply of the
|
||||
* current one.
|
||||
*/
|
||||
struct nfc_digital_ops {
|
||||
int (*in_configure_hw)(struct nfc_digital_dev *ddev, int type,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue