wireless-drivers-next patches for 4.8

Major changes:
 
 wl18xx
 
 * add initial mesh support
 
 bcma
 
 * serial flash support on non-MIPS SoCs
 
 ath10k
 
 * enable support for QCA9888
 * disable wake_tx_queue() mac80211 op for older devices to workaround
   throughput regression
 
 ath9k
 
 * implement temperature compensation support for AR9003+
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQEcBAABAgAGBQJXkilmAAoJEG4XJFUm622bWa0H/140nogmko+U1QXTSzVcNeJM
 dNPwYvkrDu5PPjWL0PekUXT8WVPk6P/SD7Sa93822BQFyR1i5QEWnXX7NMMw8WwW
 f7uhCdACHoVwIktVj+CTWmat9viknyed2/B9Qbi07tfuhDMKdfi76wHf4frPW5yP
 wygslKYgyV2Af/18puEcfLeBHDYI61AA1NEO69uPIx5WdT/71YrlwssnH8/xtSlV
 YElYyApxv7GUVx6Irj6d/YyilvElDbzQlZSLW5zfO2664LW63MGpCY5cnP7K5Nfo
 pGNVj1f3FpYK8ZncHAlNUH8bJj9snNn7RFYSo//6QAoWv7t4M2T7AbdYhNHK/ko=
 =a9OQ
 -----END PGP SIGNATURE-----

Merge tag 'wireless-drivers-next-for-davem-2016-07-22' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next

Kalle Valo says:

====================
pull-request: wireless-drivers-next 2016-07-22

I'm sick so I have to keep this short, but here's the last pull request
to net-next. This time there's a trivial conflict with mtd tree:

http://lkml.kernel.org/g/20160720123133.44dab209@canb.auug.org.au

We concluded with Brian (CCed) that it's best that we ask Linus to fix
this. The patches have been in linux-next for a couple of days. This
time I haven't done any merge tests so I don't know if there are any
other conflicts etc.

Please let me know if there are any problems.

wireless-drivers-next patches for 4.8

Major changes:

wl18xx

* add initial mesh support

bcma

* serial flash support on non-MIPS SoCs

ath10k

* enable support for QCA9888
* disable wake_tx_queue() mac80211 op for older devices to workaround
  throughput regression

ath9k

* implement temperature compensation support for AR9003+
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-07-25 11:09:19 -07:00
commit d5b160d342
78 changed files with 1179 additions and 645 deletions

View File

@ -1,19 +1,30 @@
* Texas Instruments wl1271 wireless lan controller
* Texas Instruments wl12xx/wl18xx wireless lan controller
The wl1271 chip can be connected via SPI or via SDIO. This
The wl12xx/wl18xx chips can be connected via SPI or via SDIO. This
document describes the binding for the SPI connected chip.
Required properties:
- compatible : Should be "ti,wl1271"
- compatible : Should be one of the following:
* "ti,wl1271"
* "ti,wl1273"
* "ti,wl1281"
* "ti,wl1283"
* "ti,wl1801"
* "ti,wl1805"
* "ti,wl1807"
* "ti,wl1831"
* "ti,wl1835"
* "ti,wl1837"
- reg : Chip select address of device
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
- ref-clock-frequency : Reference clock frequency
- interrupt-parent, interrupts :
Should contain parameters for 1 interrupt line.
Interrupt parameters: parent, line number, type.
- vwlan-supply : Point the node of the regulator that powers/enable the wl1271 chip
- vwlan-supply : Point the node of the regulator that powers/enable the
wl12xx/wl18xx chip
Optional properties:
- ref-clock-frequency : Reference clock frequency (should be set for wl12xx)
- clock-xtal : boolean, clock is generated from XTAL
- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
@ -21,16 +32,28 @@ Optional properties:
Examples:
For wl12xx family:
&spi1 {
wl1271@1 {
wlcore: wlcore@1 {
compatible = "ti,wl1271";
reg = <1>;
spi-max-frequency = <48000000>;
clock-xtal;
ref-clock-frequency = <38400000>;
interrupt-parent = <&gpio3>;
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
vwlan-supply = <&vwlan_fixed>;
clock-xtal;
ref-clock-frequency = <38400000>;
};
};
For wl18xx family:
&spi0 {
wlcore: wlcore@0 {
compatible = "ti,wl1835";
reg = <0>;
spi-max-frequency = <48000000>;
interrupt-parent = <&gpio0>;
interrupts = <27 IRQ_TYPE_EDGE_RISING>;
vwlan-supply = <&vwlan_fixed>;
};
};

View File

@ -76,9 +76,16 @@ config BCMA_PFLASH
default y
config BCMA_SFLASH
bool
depends on BCMA_DRIVER_MIPS
bool "ChipCommon-attached serial flash support"
depends on BCMA_HOST_SOC
default y
help
Some cheap devices have serial flash connected to the ChipCommon
instead of independent SPI controller. It requires using a separated
driver that implements ChipCommon specific interface communication.
Enabling this symbol will let bcma recognize serial flash and register
it as platform device.
config BCMA_NFLASH
bool

View File

@ -33,11 +33,12 @@ static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
{
struct bcma_bus *bus = ccb->core->bus;
void __iomem *mii = ccb->mii;
writel(offset, ccb->mii + 0x00);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
writel(value, ccb->mii + 0x04);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
writel(offset, mii + BCMA_CCB_MII_MNG_CTL);
bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
writel(value, mii + BCMA_CCB_MII_MNG_CMD_DATA);
bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
}
EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);

View File

@ -295,6 +295,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },

View File

@ -114,7 +114,7 @@ config MTD_SST25L
config MTD_BCM47XXSFLASH
tristate "R/O support for serial flash on BCMA bus"
depends on BCMA_SFLASH
depends on BCMA_SFLASH && (MIPS || ARM)
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for

View File

@ -206,6 +206,28 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
},
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
.dev_id = QCA9888_2_0_DEVICE_ID,
.name = "qca9888 hw2.0",
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
.continuous_frag_desc = true,
.channel_counters_freq_hz = 150000,
.max_probe_resp_desc_thres = 24,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
.tx_chain_mask = 3,
.rx_chain_mask = 3,
.max_spatial_stream = 2,
.cal_data_len = 12064,
.fw = {
.dir = QCA9888_HW_2_0_FW_DIR,
.board = QCA9888_HW_2_0_BOARD_DATA_FILE,
.board_size = QCA99X0_BOARD_DATA_SZ,
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
},
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
.dev_id = QCA9377_1_0_DEVICE_ID,
@ -1675,7 +1697,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
case ATH10K_FW_WMI_OP_VERSION_10_4:
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
WARN_ON(1);
ath10k_err(ar, "htt op version not found from fw meta data");
return -EINVAL;
}
}
@ -2171,6 +2193,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->regs = &qca99x0_regs;
ar->hw_values = &qca99x0_values;
break;
case ATH10K_HW_QCA9888:
ar->regs = &qca99x0_regs;
ar->hw_values = &qca9888_values;
break;
case ATH10K_HW_QCA4019:
ar->regs = &qca4019_regs;
ar->hw_values = &qca4019_values;

View File

@ -165,6 +165,13 @@ struct ath10k_fw_stats_peer {
u32 rx_duration;
};
struct ath10k_fw_extd_stats_peer {
struct list_head list;
u8 peer_macaddr[ETH_ALEN];
u32 rx_duration;
};
struct ath10k_fw_stats_vdev {
struct list_head list;
@ -256,9 +263,11 @@ struct ath10k_fw_stats_pdev {
};
struct ath10k_fw_stats {
bool extended;
struct list_head pdevs;
struct list_head vdevs;
struct list_head peers;
struct list_head peers_extd;
};
#define ATH10K_TPC_TABLE_TYPE_FLAG 1
@ -667,6 +676,7 @@ struct ath10k_fw_components {
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
struct ieee80211_ops *ops;
struct device *dev;
u8 mac_addr[ETH_ALEN];

View File

@ -313,13 +313,25 @@ static void ath10k_fw_stats_peers_free(struct list_head *head)
}
}
static void ath10k_fw_extd_stats_peers_free(struct list_head *head)
{
struct ath10k_fw_extd_stats_peer *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
{
spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false;
ar->debug.fw_stats.extended = false;
ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
spin_unlock_bh(&ar->data_lock);
}
@ -334,6 +346,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.peers);
INIT_LIST_HEAD(&stats.peers_extd);
spin_lock_bh(&ar->data_lock);
ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
@ -354,7 +367,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
* delivered which is treated as end-of-data and is itself discarded
*/
if (ath10k_peer_stats_enabled(ar))
ath10k_sta_update_rx_duration(ar, &stats.peers);
ath10k_sta_update_rx_duration(ar, &stats);
if (ar->debug.fw_stats_done) {
if (!ath10k_peer_stats_enabled(ar))
@ -396,6 +409,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
list_splice_tail_init(&stats.peers_extd,
&ar->debug.fw_stats.peers_extd);
}
complete(&ar->debug.fw_stats_complete);
@ -407,6 +422,7 @@ free:
ath10k_fw_stats_pdevs_free(&stats.pdevs);
ath10k_fw_stats_vdevs_free(&stats.vdevs);
ath10k_fw_stats_peers_free(&stats.peers);
ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
spin_unlock_bh(&ar->data_lock);
}
@ -2330,6 +2346,7 @@ int ath10k_debug_create(struct ath10k *ar)
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
return 0;
}

View File

@ -154,10 +154,15 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
#ifdef CONFIG_MAC80211_DEBUGFS
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer);
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats);
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo);
#else
static inline void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct list_head *peer)
static inline
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
}
#endif /* CONFIG_MAC80211_DEBUGFS */

View File

@ -18,13 +18,15 @@
#include "wmi-ops.h"
#include "debug.h"
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
{ struct ieee80211_sta *sta;
struct ath10k_fw_stats_peer *peer;
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
struct ath10k_fw_extd_stats_peer *peer;
struct ieee80211_sta *sta;
struct ath10k_sta *arsta;
rcu_read_lock();
list_for_each_entry(peer, head, list) {
list_for_each_entry(peer, &stats->peers_extd, list) {
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
NULL);
if (!sta)
@ -35,6 +37,48 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
rcu_read_unlock();
}
static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
struct ath10k_fw_stats_peer *peer;
struct ieee80211_sta *sta;
struct ath10k_sta *arsta;
rcu_read_lock();
list_for_each_entry(peer, &stats->peers, list) {
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
NULL);
if (!sta)
continue;
arsta = (struct ath10k_sta *)sta->drv_priv;
arsta->rx_duration += (u64)peer->rx_duration;
}
rcu_read_unlock();
}
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
if (stats->extended)
ath10k_sta_update_extd_stats_rx_duration(ar, stats);
else
ath10k_sta_update_stats_rx_duration(ar, stats);
}
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
struct ath10k *ar = arsta->arvif->ar;
if (!ath10k_peer_stats_enabled(ar))
return;
sinfo->rx_duration = arsta->rx_duration;
sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
}
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@ -249,28 +293,6 @@ static const struct file_operations fops_delba = {
.llseek = default_llseek,
};
static ssize_t ath10k_dbg_sta_read_rx_duration(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_sta *sta = file->private_data;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
char buf[100];
int len = 0;
len = scnprintf(buf, sizeof(buf),
"%llu usecs\n", arsta->rx_duration);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_rx_duration = {
.read = ath10k_dbg_sta_read_rx_duration,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
@ -279,6 +301,4 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
debugfs_create_file("rx_duration", S_IRUGO, dir, sta,
&fops_rx_duration);
}

View File

@ -22,7 +22,6 @@
#include <linux/list.h>
#include <linux/bug.h>
#include <linux/skbuff.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
struct ath10k;

View File

@ -748,7 +748,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd)
if (WARN_ON_ONCE(!arvif))
return NULL;
if (WARN_ON_ONCE(ath10k_mac_vif_chan(arvif->vif, &def)))
if (ath10k_mac_vif_chan(arvif->vif, &def))
return NULL;
return def.chan;
@ -2307,12 +2307,10 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_htt_rx_delba(ar, resp);
break;
case HTT_T2H_MSG_TYPE_PKTLOG: {
struct ath10k_pktlog_hdr *hdr =
(struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
sizeof(*hdr) +
__le16_to_cpu(hdr->size));
skb->len -
offsetof(struct htt_resp,
pktlog_msg.payload));
break;
}
case HTT_T2H_MSG_TYPE_RX_FLUSH: {

View File

@ -49,7 +49,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta = (void *)txq->sta->drv_priv;
struct ath10k_sta *arsta;
struct ath10k_vif *arvif = (void *)txq->vif->drv_priv;
unsigned long frame_cnt;
unsigned long byte_cnt;
@ -67,10 +67,12 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL)
return;
if (txq->sta)
if (txq->sta) {
arsta = (void *)txq->sta->drv_priv;
peer_id = arsta->peer_id;
else
} else {
peer_id = arvif->peer_id;
}
tid = txq->tid;
bit = BIT(peer_id % 32);
@ -388,6 +390,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
{
int size;
tasklet_kill(&htt->txrx_compl_task);
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
idr_destroy(&htt->pending_tx);
@ -733,16 +737,18 @@ static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
struct ath10k_vif *arvif;
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
return ar->scan.vdev_id;
else if (cb->vif)
} else if (cb->vif) {
arvif = (void *)cb->vif->drv_priv;
return arvif->vdev_id;
else if (ar->monitor_started)
} else if (ar->monitor_started) {
return ar->monitor_vdev_id;
else
} else {
return 0;
}
}
static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth)

View File

@ -19,7 +19,6 @@
#include "hw.h"
const struct ath10k_hw_regs qca988x_regs = {
.rtc_state_cold_reset_mask = 0x00000400,
.rtc_soc_base_address = 0x00004000,
.rtc_wmac_base_address = 0x00005000,
.soc_core_base_address = 0x00009000,
@ -46,7 +45,6 @@ const struct ath10k_hw_regs qca988x_regs = {
};
const struct ath10k_hw_regs qca6174_regs = {
.rtc_state_cold_reset_mask = 0x00002000,
.rtc_soc_base_address = 0x00000800,
.rtc_wmac_base_address = 0x00001000,
.soc_core_base_address = 0x0003a000,
@ -73,7 +71,6 @@ const struct ath10k_hw_regs qca6174_regs = {
};
const struct ath10k_hw_regs qca99x0_regs = {
.rtc_state_cold_reset_mask = 0x00000400,
.rtc_soc_base_address = 0x00080000,
.rtc_wmac_base_address = 0x00000000,
.soc_core_base_address = 0x00082000,
@ -168,6 +165,15 @@ const struct ath10k_hw_values qca99x0_values = {
.ce_desc_meta_data_lsb = 4,
};
const struct ath10k_hw_values qca9888_values = {
.rtc_state_val_on = 3,
.ce_count = 12,
.msi_assign_ce_max = 12,
.num_target_ce_config_wlan = 10,
.ce_desc_meta_data_mask = 0xFFF0,
.ce_desc_meta_data_lsb = 4,
};
const struct ath10k_hw_values qca4019_values = {
.ce_count = 12,
.num_target_ce_config_wlan = 10,
@ -198,7 +204,8 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
case ATH10K_HW_CC_WRAP_SHIFTED_EACH:
if (cc < cc_prev)
cc_fix = 0x7fffffff;
else
if (rcc < rcc_prev)
rcc_fix = 0x7fffffff;
break;
case ATH10K_HW_CC_WRAP_DISABLED:

View File

@ -26,6 +26,7 @@
#define QCA6164_2_1_DEVICE_ID (0x0041)
#define QCA6174_2_1_DEVICE_ID (0x003e)
#define QCA99X0_2_0_DEVICE_ID (0x0040)
#define QCA9888_2_0_DEVICE_ID (0x0056)
#define QCA9984_1_0_DEVICE_ID (0x0046)
#define QCA9377_1_0_DEVICE_ID (0x0042)
#define QCA9887_1_0_DEVICE_ID (0x0050)
@ -108,6 +109,14 @@ enum qca9377_chip_id_rev {
#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA9888 2.0 defines */
#define QCA9888_HW_2_0_DEV_VERSION 0x1000000
#define QCA9888_HW_DEV_TYPE 0xc
#define QCA9888_HW_2_0_CHIP_ID_REV 0x0
#define QCA9888_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA9888/hw2.0"
#define QCA9888_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA9888_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9377 1.0 definitions */
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
@ -210,6 +219,7 @@ enum ath10k_hw_rev {
ATH10K_HW_QCA988X,
ATH10K_HW_QCA6174,
ATH10K_HW_QCA99X0,
ATH10K_HW_QCA9888,
ATH10K_HW_QCA9984,
ATH10K_HW_QCA9377,
ATH10K_HW_QCA4019,
@ -217,7 +227,6 @@ enum ath10k_hw_rev {
};
struct ath10k_hw_regs {
u32 rtc_state_cold_reset_mask;
u32 rtc_soc_base_address;
u32 rtc_wmac_base_address;
u32 soc_core_base_address;
@ -260,6 +269,7 @@ struct ath10k_hw_values {
extern const struct ath10k_hw_values qca988x_values;
extern const struct ath10k_hw_values qca6174_values;
extern const struct ath10k_hw_values qca99x0_values;
extern const struct ath10k_hw_values qca9888_values;
extern const struct ath10k_hw_values qca4019_values;
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
@ -269,6 +279,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
#define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
#define QCA_REV_9888(ar) ((ar)->hw_rev == ATH10K_HW_QCA9888)
#define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984)
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
@ -296,25 +307,6 @@ enum ath10k_mcast2ucast_mode {
ATH10K_MCAST2UCAST_ENABLED = 1,
};
struct ath10k_pktlog_hdr {
__le16 flags;
__le16 missed_cnt;
__le16 log_type;
__le16 size;
__le32 timestamp;
u8 payload[0];
} __packed;
struct ath10k_pktlog_10_4_hdr {
__le16 flags;
__le16 missed_cnt;
__le16 log_type;
__le16 size;
__le32 timestamp;
__le32 type_specific_data;
u8 payload[0];
} __packed;
enum ath10k_hw_rate_ofdm {
ATH10K_HW_RATE_OFDM_48M = 0,
ATH10K_HW_RATE_OFDM_24M,
@ -535,7 +527,6 @@ enum ath10k_hw_cc_wraparound_type {
/* as of IP3.7.1 */
#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on
#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask
#define RTC_STATE_V_LSB 0
#define RTC_STATE_V_MASK 0x00000007
#define RTC_STATE_ADDRESS 0x0000

View File

@ -802,6 +802,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
{
struct ath10k_peer *peer, *tmp;
int peer_id;
int i;
lockdep_assert_held(&ar->conf_mutex);
@ -818,6 +819,17 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
ar->peer_map[peer_id] = NULL;
}
/* Double check that peer is properly un-referenced from
* the peer_map
*/
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
if (ar->peer_map[i] == peer) {
ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %p idx %d)\n",
peer->addr, peer, i);
ar->peer_map[i] = NULL;
}
}
list_del(&peer->list);
kfree(peer);
ar->num_peers--;
@ -828,6 +840,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
static void ath10k_peer_cleanup_all(struct ath10k *ar)
{
struct ath10k_peer *peer, *tmp;
int i;
lockdep_assert_held(&ar->conf_mutex);
@ -836,6 +849,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
list_del(&peer->list);
kfree(peer);
}
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++)
ar->peer_map[i] = NULL;
spin_unlock_bh(&ar->data_lock);
ar->num_peers = 0;
@ -2939,7 +2956,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
if (channel->flags & IEEE80211_CHAN_DISABLED)
continue;
ch->allow_ht = true;
ch->allow_ht = true;
/* FIXME: when should we really allow VHT? */
ch->allow_vht = true;
@ -3675,17 +3692,18 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
{
struct ath10k_txq *artxq = (void *)txq->drv_priv;
struct ath10k_txq *artxq;
if (!txq)
return;
artxq = (void *)txq->drv_priv;
INIT_LIST_HEAD(&artxq->list);
}
static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
{
struct ath10k_txq *artxq = (void *)txq->drv_priv;
struct ath10k_txq *artxq;
struct ath10k_skb_cb *cb;
struct sk_buff *msdu;
int msdu_id;
@ -3693,6 +3711,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
if (!txq)
return;
artxq = (void *)txq->drv_priv;
spin_lock_bh(&ar->txqs_lock);
if (!list_empty(&artxq->list))
list_del_init(&artxq->list);
@ -4228,6 +4247,9 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
}
if (ar->cfg_tx_chainmask <= 1)
vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC;
vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
@ -4265,7 +4287,7 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
ht_cap.cap |= smps;
}
if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC)
if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC && (ar->cfg_tx_chainmask > 1))
ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) {
@ -5979,9 +6001,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
continue;
if (peer->sta == sta) {
ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n",
sta->addr, arvif->vdev_id);
ath10k_warn(ar, "found sta peer %pM (ptr %p id %d) entry on vdev %i after it was supposedly removed\n",
sta->addr, peer, i, arvif->vdev_id);
peer->sta = NULL;
/* Clean up the peer object as well since we
* must have failed to do this above.
*/
list_del(&peer->list);
ar->peer_map[i] = NULL;
kfree(peer);
ar->num_peers--;
}
}
spin_unlock_bh(&ar->data_lock);
@ -7406,6 +7436,7 @@ static const struct ieee80211_ops ath10k_ops = {
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs,
.sta_statistics = ath10k_sta_statistics,
#endif
};
@ -7475,21 +7506,32 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
struct ath10k *ath10k_mac_create(size_t priv_size)
{
struct ieee80211_hw *hw;
struct ieee80211_ops *ops;
struct ath10k *ar;
hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
if (!hw)
ops = kmemdup(&ath10k_ops, sizeof(ath10k_ops), GFP_KERNEL);
if (!ops)
return NULL;
hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops);
if (!hw) {
kfree(ops);
return NULL;
}
ar = hw->priv;
ar->hw = hw;
ar->ops = ops;
return ar;
}
void ath10k_mac_destroy(struct ath10k *ar)
{
struct ieee80211_ops *ops = ar->ops;
ieee80211_free_hw(ar->hw);
kfree(ops);
}
static const struct ieee80211_iface_limit ath10k_if_limits[] = {
@ -7923,6 +7965,15 @@ int ath10k_mac_register(struct ath10k *ar)
ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
}
/* Current wake_tx_queue implementation imposes a significant
* performance penalty in some setups. The tx scheduling code needs
* more work anyway so disable the wake_tx_queue unless firmware
* supports the pull-push mechanism.
*/
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
ar->running_fw->fw_file.fw_features))
ar->ops->wake_tx_queue = NULL;
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier);
if (ret) {

View File

@ -56,6 +56,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
{ PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
{ PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */
{ PCI_VDEVICE(ATHEROS, QCA9888_2_0_DEVICE_ID) }, /* PCI-E QCA9888 V2 */
{ PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */
{ PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */
{ PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */
@ -85,6 +86,8 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
{ QCA9984_1_0_DEVICE_ID, QCA9984_HW_1_0_CHIP_ID_REV },
{ QCA9888_2_0_DEVICE_ID, QCA9888_HW_2_0_CHIP_ID_REV },
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV },
@ -850,6 +853,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
CORE_CTRL_ADDRESS) &
0x7ff) << 21;
break;
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA4019:
@ -1583,6 +1587,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
break;
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0
* to mask irq/MSI.
@ -1608,6 +1613,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
break;
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0
* to unmask irq/MSI.
@ -1948,6 +1954,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
switch (ar_pci->pdev->device) {
case QCA988X_2_0_DEVICE_ID:
case QCA99X0_2_0_DEVICE_ID:
case QCA9888_2_0_DEVICE_ID:
case QCA9984_1_0_DEVICE_ID:
case QCA9887_1_0_DEVICE_ID:
return 1;
@ -2216,6 +2223,14 @@ static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
}
static bool ath10k_pci_has_device_gone(struct ath10k *ar)
{
u32 val;
val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
return (val == 0xffffffff);
}
/* this function effectively clears target memory controller assert line */
static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
{
@ -2748,6 +2763,9 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret;
if (ath10k_pci_has_device_gone(ar))
return IRQ_NONE;
ret = ath10k_pci_force_wake(ar);
if (ret) {
ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
@ -3169,6 +3187,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
break;
case QCA9888_2_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA9888;
pci_ps = false;
pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
break;
case QCA9377_1_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA9377;
pci_ps = true;

View File

@ -101,9 +101,9 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
break;
case 80:
/* TODO: As experiments with an analogue sender and various
* configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
* configurations (fft-sizes of 64/128/256 and 20/40/80 Mhz)
* show, the particular configuration of 80 MHz/64 bins does
* not match with the other smaples at all. Until the reason
* not match with the other samples at all. Until the reason
* for that is found, don't report these samples.
*/
if (bin_len == 64)

View File

@ -81,10 +81,11 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
skb_cb = ATH10K_SKB_CB(msdu);
txq = skb_cb->txq;
artxq = (void *)txq->drv_priv;
if (txq)
if (txq) {
artxq = (void *)txq->drv_priv;
artxq->num_fw_queued--;
}
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
ath10k_htt_tx_dec_pending(htt);
@ -216,6 +217,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
ev->vdev_id, ev->addr, ev->peer_id);
WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer));
ar->peer_map[ev->peer_id] = peer;
set_bit(ev->peer_id, peer->peer_ids);
exit:

View File

@ -1826,7 +1826,7 @@ static struct sk_buff *
ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
struct ath10k_vif *arvif;
struct wmi_mgmt_tx_cmd *cmd;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
@ -1838,10 +1838,12 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
hdr = (struct ieee80211_hdr *)msdu->data;
fc = le16_to_cpu(hdr->frame_control);
if (cb->vif)
if (cb->vif) {
arvif = (void *)cb->vif->drv_priv;
vdev_id = arvif->vdev_id;
else
} else {
vdev_id = 0;
}
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
return ERR_PTR(-EINVAL);
@ -2924,6 +2926,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
u32 num_pdev_ext_stats;
u32 num_vdev_stats;
u32 num_peer_stats;
u32 num_bcnflt_stats;
u32 stats_id;
int i;
@ -2934,6 +2937,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats);
stats_id = __le32_to_cpu(ev->stats_id);
for (i = 0; i < num_pdev_stats; i++) {
@ -2974,32 +2978,57 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
/* fw doesn't implement vdev stats */
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10_4_peer_extd_stats *src;
const struct wmi_10_4_peer_stats *src;
struct ath10k_fw_stats_peer *dst;
int stats_len;
bool extd_peer_stats = !!(stats_id & WMI_10_4_STAT_PEER_EXTD);
if (extd_peer_stats)
stats_len = sizeof(struct wmi_10_4_peer_extd_stats);
else
stats_len = sizeof(struct wmi_10_4_peer_stats);
src = (void *)skb->data;
if (!skb_pull(skb, stats_len))
if (!skb_pull(skb, sizeof(*src)))
return -EPROTO;
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst)
continue;
ath10k_wmi_10_4_pull_peer_stats(&src->common, dst);
/* FIXME: expose 10.4 specific values */
if (extd_peer_stats)
dst->rx_duration = __le32_to_cpu(src->rx_duration);
ath10k_wmi_10_4_pull_peer_stats(src, dst);
list_add_tail(&dst->list, &stats->peers);
}
for (i = 0; i < num_bcnflt_stats; i++) {
const struct wmi_10_4_bss_bcn_filter_stats *src;
src = (void *)skb->data;
if (!skb_pull(skb, sizeof(*src)))
return -EPROTO;
/* FIXME: expose values to userspace
*
* Note: Even though this loop seems to do nothing it is
* required to parse following sub-structures properly.
*/
}
if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0)
return 0;
stats->extended = true;
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10_4_peer_extd_stats *src;
struct ath10k_fw_extd_stats_peer *dst;
src = (void *)skb->data;
if (!skb_pull(skb, sizeof(*src)))
return -EPROTO;
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst)
continue;
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
dst->rx_duration = __le32_to_cpu(src->rx_duration);
list_add_tail(&dst->list, &stats->peers_extd);
}
return 0;
}
@ -5257,6 +5286,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_PEER_STA_KICKOUT_EVENTID:
ath10k_wmi_event_peer_sta_kickout(ar, skb);
break;
case WMI_10_4_ROAM_EVENTID:
ath10k_wmi_event_roam(ar, skb);
break;
case WMI_10_4_HOST_SWBA_EVENTID:
ath10k_wmi_event_host_swba(ar, skb);
break;
@ -7903,6 +7935,7 @@ static const struct wmi_ops wmi_10_4_ops = {
.pull_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev,
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
.pull_roam_ev = ath10k_wmi_op_pull_roam_ev,
.get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,

View File

@ -4340,7 +4340,6 @@ struct wmi_10_4_peer_stats {
} __packed;
struct wmi_10_4_peer_extd_stats {
struct wmi_10_4_peer_stats common;
struct wmi_mac_addr peer_macaddr;
__le32 inactive_time;
__le32 peer_chain_rssi;
@ -4348,6 +4347,19 @@ struct wmi_10_4_peer_extd_stats {
__le32 reserved[10];
} __packed;
struct wmi_10_4_bss_bcn_stats {
__le32 vdev_id;
__le32 bss_bcns_dropped;
__le32 bss_bcn_delivered;
} __packed;
struct wmi_10_4_bss_bcn_filter_stats {
__le32 bcns_dropped;
__le32 bcns_delivered;
__le32 active_filters;
struct wmi_10_4_bss_bcn_stats bss_stats;
} __packed;
struct wmi_10_2_pdev_ext_stats {
__le32 rx_rssi_comb;
__le32 rx_rssi[4];

View File

@ -847,8 +847,6 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
up(&ar->sem);
vif->sme_state = SME_DISCONNECTED;
return 0;
}
@ -1111,7 +1109,8 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
cfg80211_chandef_create(&chandef,
ieee80211_get_channel(vif->ar->wiphy, freq),
(mode == WMI_11G_HT20) ?
(mode == WMI_11G_HT20 &&
ath6kl_band_2ghz.ht_cap.ht_supported) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
mutex_lock(&vif->wdev.mtx);
@ -2978,6 +2977,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
clear_bit(CONNECTED, &vif->flags);
netif_carrier_off(vif->ndev);
/* Restore ht setting in firmware */
return ath6kl_restore_htcap(vif);

View File

@ -1401,6 +1401,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return;
}
pad_before_data_start =
(le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
& WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
/* Get the Power save state of the STA */
if (vif->nw_type == AP_NETWORK) {
meta_type = wmi_data_hdr_get_meta(dhdr);
@ -1408,7 +1412,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) &
WMI_DATA_HDR_PS_MASK);
offset = sizeof(struct wmi_data_hdr);
offset = sizeof(struct wmi_data_hdr) + pad_before_data_start;
trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG);
switch (meta_type) {
@ -1523,9 +1527,6 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
seq_no = wmi_data_hdr_get_seqno(dhdr);
meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(dhdr);
pad_before_data_start =
(le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT)
& WMI_DATA_HDR_PAD_BEFORE_DATA_MASK;
skb_pull(skb, sizeof(struct wmi_data_hdr));

View File

@ -18,7 +18,6 @@
#include <linux/nl80211.h>
#include <linux/platform_device.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h>
#include "ath9k.h"
@ -58,20 +57,9 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
struct ath_softc *sc = (struct ath_softc *)common->priv;
struct platform_device *pdev = to_platform_device(sc->dev);
struct ath9k_platform_data *pdata;
pdata = dev_get_platdata(&pdev->dev);
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
ath_err(common,
"%s: flash read failed, offset %08x is out of range\n",
__func__, off);
return false;
}
*data = pdata->eeprom_data[off];
return true;
ath_err(common, "%s: eeprom data has to be provided externally\n",
__func__);
return false;
}
static struct ath_bus_ops ath_ahb_bus_ops = {

View File

@ -476,6 +476,7 @@ static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
struct ath_spec_scan *param)
{
u32 repeat_bit;
u8 count;
if (!param->enabled) {
@ -486,12 +487,15 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
if (param->short_repeat)
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
if (AR_SREV_9280(ah))
repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI;
if (param->short_repeat)
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit);
else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit);
/* on AR92xx, the highest bit of count will make the the chip send
* spectral samples endlessly. Check if this really was intended,
@ -499,15 +503,25 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
*/
count = param->count;
if (param->endless) {
if (AR_SREV_9271(ah))
count = 0;
else
if (AR_SREV_9280(ah))
count = 0x80;
else
count = 0;
} else if (count & 0x80)
count = 0x7f;
else if (!count)
count = 1;
if (AR_SREV_9280(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_COUNT, count);
} else {
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT);
}
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_COUNT, count);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,

View File

@ -177,8 +177,11 @@
#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/
#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/
#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/
#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000
#define AR_PHY_RX_DELAY 0x9914
#define AR_PHY_SEARCH_START_DELAY 0x9918

View File

@ -33,6 +33,7 @@ struct coeff {
enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0),
TEMP_COMP_CAL = BIT(1),
};
static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@ -58,6 +59,12 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
/* Kick-off cal */
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
break;
case TEMP_COMP_CAL:
ath_dbg(common, CALIBRATE,
"starting Temperature Compensation Calibration\n");
REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL);
REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START);
break;
default:
ath_err(common, "Invalid calibration type\n");
break;
@ -75,50 +82,51 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
{
struct ath9k_hw_cal_data *caldata = ah->caldata;
/* Cal is assumed not done until explicitly set below */
bool iscaldone = false;
const struct ath9k_percal_data *cur_caldata = currCal->calData;
/* Calibration in progress. */
if (currCal->calState == CAL_RUNNING) {
/* Check to see if it has finished. */
if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)
return false;
/*
* Accumulate cal measures for active chains
*/
if (cur_caldata->calCollect)
cur_caldata->calCollect(ah);
ah->cal_samples++;
if (ah->cal_samples >= cur_caldata->calNumSamples) {
unsigned int i, numChains = 0;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (rxchainmask & (1 << i))
numChains++;
}
/*
* Accumulate cal measures for active chains
* Process accumulated data
*/
currCal->calData->calCollect(ah);
ah->cal_samples++;
if (cur_caldata->calPostProc)
cur_caldata->calPostProc(ah, numChains);
if (ah->cal_samples >=
currCal->calData->calNumSamples) {
unsigned int i, numChains = 0;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (rxchainmask & (1 << i))
numChains++;
}
/*
* Process accumulated data
*/
currCal->calData->calPostProc(ah, numChains);
/* Calibration has finished. */
caldata->CalValid |= currCal->calData->calType;
currCal->calState = CAL_DONE;
iscaldone = true;
} else {
/* Calibration has finished. */
caldata->CalValid |= cur_caldata->calType;
currCal->calState = CAL_DONE;
return true;
} else {
/*
* Set-up collection of another sub-sample until we
* get desired number
*/
ar9003_hw_setup_calibration(ah, currCal);
}
}
} else if (!(caldata->CalValid & currCal->calData->calType)) {
} else if (!(caldata->CalValid & cur_caldata->calType)) {
/* If current cal is marked invalid in channel, kick it off */
ath9k_hw_reset_calibration(ah, currCal);
}
return iscaldone;
return false;
}
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
@ -315,9 +323,16 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
ar9003_hw_iqcalibrate
};
static const struct ath9k_percal_data temp_cal_single_sample = {
TEMP_COMP_CAL,
MIN_CAL_SAMPLES,
PER_MAX_LOG_COUNT,
};
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
{
ah->iq_caldata.calData = &iq_cal_single_sample;
ah->temp_caldata.calData = &temp_cal_single_sample;
if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->enabled_cals |= TX_IQ_CAL;
@ -325,7 +340,7 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
}
ah->supp_cals = IQ_MISMATCH_CAL;
ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL;
}
#define OFF_UPPER_LT 24
@ -1374,6 +1389,29 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
}
}
static void ar9003_hw_init_cal_common(struct ath_hw *ah)
{
struct ath9k_hw_cal_data *caldata = ah->caldata;
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
INIT_CAL(&ah->temp_caldata);
INSERT_CAL(ah, &ah->temp_caldata);
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;
if (ah->cal_list_curr)
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
if (caldata)
caldata->CalValid = 0;
}
static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -1533,21 +1571,7 @@ skip_tx_iqcal:
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;
if (ah->cal_list_curr)
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
if (caldata)
caldata->CalValid = 0;
ar9003_hw_init_cal_common(ah);
return true;
}
@ -1578,8 +1602,6 @@ static bool do_ar9003_agc_cal(struct ath_hw *ah)
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false;
bool status = true;
bool run_agc_cal = false, sep_iq_cal = false;
@ -1677,21 +1699,7 @@ skip_tx_iqcal:
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;
if (ah->cal_list_curr)
ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
if (caldata)
caldata->CalValid = 0;
ar9003_hw_init_cal_common(ah);
return true;
}

View File

@ -4175,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
ar9003_hw_internal_regulator_apply(ah);
ar9003_hw_apply_tuning_caps(ah);
ar9003_hw_apply_minccapwr_thresh(ah, chan);
ar9003_hw_apply_minccapwr_thresh(ah, is2ghz);
ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
ar9003_hw_thermometer_apply(ah);
ar9003_hw_thermo_cal_apply(ah);

View File

@ -689,13 +689,6 @@
#define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300)
#define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8)
#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \
((AR_SREV_9485(ah) ? 0x1628c : 0x16294)))
#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
#define AR_CH0_THERM_XPASHORT2GND 0x4
#define AR_CH0_THERM_XPASHORT2GND_S 2
#define AR_SWITCH_TABLE_COM_ALL (0xffff)
#define AR_SWITCH_TABLE_COM_ALL_S (0)
#define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff)
@ -712,15 +705,17 @@
#define AR_SWITCH_TABLE_ALL (0xfff)
#define AR_SWITCH_TABLE_ALL_S (0)
#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c))
#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c))
#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
#define AR_CH0_THERM_XPASHORT2GND 0x4
#define AR_CH0_THERM_XPASHORT2GND_S 2
#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000
#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
#define AR_PHY_65NM_CH0_THERM_START 0x20000000
#define AR_PHY_65NM_CH0_THERM_START_S 29
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
#define AR_CH0_THERM_LOCAL 0x80000000
#define AR_CH0_THERM_START 0x20000000
#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00
#define AR_CH0_THERM_SAR_ADC_OUT_S 8
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
(AR_SREV_9462(ah) ? 0x16290 : 0x16284))

View File

@ -637,6 +637,8 @@ struct ath9k_vif_iter_data {
int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */
int nocbs; /* number of OCB vifs */
int nbcnvifs; /* number of beaconing vifs */
struct ieee80211_vif *primary_beacon_vif;
struct ieee80211_vif *primary_sta;
};
@ -685,10 +687,11 @@ struct ath_beacon {
};
void ath9k_beacon_tasklet(unsigned long data);
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
u32 changed);
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
bool beacons);
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc);
void ath9k_set_beacon(struct ath_softc *sc);
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_csa_update(struct ath_softc *sc);

View File

@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
if (ah->slottime == ATH9K_SLOT_TIME_20)
if (ah->slottime == 20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
}
sc->beacon.bslot[avp->av_bslot] = vif;
sc->nbcnvifs++;
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
avp->av_bslot);
@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_buf *bf = avp->av_bcbuf;
struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
avp->av_bslot);
tasklet_disable(&sc->bcon_tasklet);
cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
if (bf && bf->bf_mpdu) {
struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr,
@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
avp->av_bcbuf = NULL;
sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
list_add_tail(&bf->list, &sc->beacon.bbuf);
tasklet_enable(&sc->bcon_tasklet);
}
void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_vif *vif;
struct ath_vif *avp;
s64 tsfadjust;
u32 offset;
int first_slot = ATH_BCBUF;
int slot;
tasklet_disable(&sc->bcon_tasklet);
/* Find first taken slot. */
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (sc->beacon.bslot[slot]) {
first_slot = slot;
break;
}
}
if (first_slot == 0)
goto out;
/* Re-enumarate all slots, moving them forward. */
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (slot + first_slot < ATH_BCBUF) {
vif = sc->beacon.bslot[slot + first_slot];
sc->beacon.bslot[slot] = vif;
if (vif) {
avp = (void *)vif->drv_priv;
avp->av_bslot = slot;
}
} else {
sc->beacon.bslot[slot] = NULL;
}
}
vif = sc->beacon.bslot[0];
if (WARN_ON(!vif))
goto out;
/* Get the tsf_adjust value for the new first slot. */
avp = (void *)vif->drv_priv;
tsfadjust = le64_to_cpu(avp->tsf_adjust);
ath_dbg(common, CONFIG,
"Adjusting global TSF after beacon slot reassignment: %lld\n",
(signed long long)tsfadjust);
/* Modify TSF as required and update the HW. */
avp->chanctx->tsf_val += tsfadjust;
if (sc->cur_chan == avp->chanctx) {
offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset);
}
/* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
out:
tasklet_enable(&sc->bcon_tasklet);
}
static int ath9k_beacon_choose_slot(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -274,22 +331,33 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
return slot;
}
static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
static void ath9k_set_tsfadjust(struct ath_softc *sc,
struct ath_beacon_config *cur_conf)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
u32 tsfadjust;
s64 tsfadjust;
int slot;
if (avp->av_bslot == 0)
return;
for (slot = 0; slot < ATH_BCBUF; slot++) {
struct ath_vif *avp;
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
if (!sc->beacon.bslot[slot])
continue;
ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
(unsigned long long)tsfadjust, avp->av_bslot);
avp = (void *)sc->beacon.bslot[slot]->drv_priv;
/* tsf_adjust is added to the TSF value. We send out the
* beacon late, so need to adjust the TSF starting point to be
* later in time (i.e. the theoretical first beacon has a TSF
* of 0 after correction).
*/
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
(signed long long)tsfadjust, avp->av_bslot);
}
}
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
@ -443,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data)
* Both nexttbtt and intval have to be in usecs.
*/
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
u32 intval, bool reset_tsf)
u32 intval)
{
struct ath_hw *ah = sc->sc_ah;
ath9k_hw_disable_interrupts(ah);
if (reset_tsf)
ath9k_hw_reset_tsf(ah);
ath9k_beaconq_config(sc);
ath9k_hw_beaconinit(ah, nexttbtt, intval);
ah->imask |= ATH9K_INT_SWBA;
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
}
static void ath9k_beacon_stop(struct ath_softc *sc)
{
ath9k_hw_disable_interrupts(sc->sc_ah);
sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah);
ath9k_hw_enable_interrupts(sc->sc_ah);
}
/*
* For multi-bss ap support beacons are either staggered evenly over N slots or
* burst together. For the former arrange for the SWBA to be delivered for each
@ -468,7 +544,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
}
static void ath9k_beacon_config_sta(struct ath_hw *ah,
@ -497,7 +573,7 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
ath9k_cmn_beacon_config_adhoc(ah, conf);
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);
ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
/*
* Set the global 'beacon has been configured' flag for the
@ -507,44 +583,6 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
set_bit(ATH_OP_BEACONS, &common->op_flags);
}
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
if (ath9k_is_chanctx_enabled()) {
/*
* If the VIF is not present in the current channel context,
* then we can't do the usual opmode checks. Allow the
* beacon config for the VIF to be updated in this case and
* return immediately.
*/
if (sc->cur_chan != avp->chanctx)
return true;
}
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if (vif->type != NL80211_IFTYPE_AP) {
ath_dbg(common, CONFIG,
"An AP interface is already present !\n");
return false;
}
}
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
if ((vif->type == NL80211_IFTYPE_STATION) &&
test_bit(ATH_OP_BEACONS, &common->op_flags) &&
vif != sc->cur_chan->primary_sta) {
ath_dbg(common, CONFIG,
"Beacon already configured for a station interface\n");
return false;
}
}
return true;
}
static void ath9k_cache_beacon_config(struct ath_softc *sc,
struct ath_chanctx *ctx,
struct ieee80211_bss_conf *bss_conf)
@ -580,87 +618,79 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
ath9k_set_tsfadjust(sc, cur_conf);
}
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
u32 changed)
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
bool beacons)
{
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_chanctx *ctx = avp->chanctx;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp;
struct ath_chanctx *ctx;
struct ath_beacon_config *cur_conf;
unsigned long flags;
bool enabled;
bool skip_beacon = false;
if (!ctx)
if (!beacons) {
clear_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_beacon_stop(sc);
return;
}
if (WARN_ON(!main_vif))
return;
cur_conf = &avp->chanctx->beacon;
if (vif->type == NL80211_IFTYPE_AP)
ath9k_set_tsfadjust(sc, vif);
avp = (void *)main_vif->drv_priv;
ctx = avp->chanctx;
cur_conf = &ctx->beacon;
enabled = cur_conf->enable_beacon;
cur_conf->enable_beacon = beacons;
if (!ath9k_allow_beacon_config(sc, vif))
return;
if (vif->type == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, ctx, bss_conf);
if (ctx != sc->cur_chan)
return;
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
ath9k_set_beacon(sc);
set_bit(ATH_OP_BEACONS, &common->op_flags);
return;
}
/*
* Take care of multiple interfaces when
* enabling/disabling SWBA.
*/
if (changed & BSS_CHANGED_BEACON_ENABLED) {
bool enabled = cur_conf->enable_beacon;
if (!bss_conf->enable_beacon) {
cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
} else {
cur_conf->enable_beacon |= BIT(avp->av_bslot);
if (!enabled)
ath9k_cache_beacon_config(sc, ctx, bss_conf);
}
}
if (ctx != sc->cur_chan)
return;
/* Update the beacon configuration. */
ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
/*
* Configure the HW beacon registers only when we have a valid
* beacon interval.
*/
if (cur_conf->beacon_interval) {
/*
* If we are joining an existing IBSS network, start beaconing
* only after a TSF-sync has taken place. Ensure that this
* happens by setting the appropriate flags.
/* Special case to sync the TSF when joining an existing IBSS.
* This is only done if no AP interface is active.
* Note that mac80211 always resets the TSF when creating a new
* IBSS interface.
*/
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
bss_conf->enable_beacon) {
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
!enabled && beacons && !main_vif->bss_conf.ibss_creator) {
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
skip_beacon = true;
} else {
ath9k_set_beacon(sc);
}
/*
* Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
* here, it is done in ath9k_beacon_config_adhoc().
*/
if (cur_conf->enable_beacon && !skip_beacon)
if (beacons && !skip_beacon) {
set_bit(ATH_OP_BEACONS, &common->op_flags);
else
ath9k_set_beacon(sc);
} else {
clear_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_beacon_stop(sc);
}
} else {
clear_bit(ATH_OP_BEACONS, &common->op_flags);
ath9k_beacon_stop(sc);
}
}

View File

@ -50,6 +50,7 @@
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
struct ath_beacon_config {
struct ieee80211_vif *main_vif;
int beacon_interval;
u16 dtim_period;
u16 bmiss_timeout;

View File

@ -280,7 +280,7 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
{
/* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = &ah->dynack;
an->ackto = ackto;
@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
void ath_dynack_reset(struct ath_hw *ah)
{
/* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = &ah->dynack;
da->lto = jiffies;

View File

@ -15,6 +15,7 @@
*/
#include "hw.h"
#include <linux/ath9k_platform.h>
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
{
@ -108,26 +109,42 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
}
}
static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off,
u16 *data)
static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
off_t offset, u16 *data)
{
u16 *blob_data;
if (off * sizeof(u16) > ah->eeprom_blob->size)
if (offset > blob_size)
return false;
blob_data = (u16 *)ah->eeprom_blob->data;
*data = blob_data[off];
*data = blob[offset];
return true;
}
static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
off_t offset, u16 *data)
{
return ath9k_hw_nvram_read_array(pdata->eeprom_data,
ARRAY_SIZE(pdata->eeprom_data),
offset, data);
}
static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
off_t offset, u16 *data)
{
return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data,
eeprom_blob->size / sizeof(u16),
offset, data);
}
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_platform_data *pdata = ah->dev->platform_data;
bool ret;
if (ah->eeprom_blob)
ret = ath9k_hw_nvram_read_blob(ah, off, data);
ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
else if (pdata && !pdata->use_eeprom && pdata->eeprom_data)
ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
else
ret = common->bus_ops->eeprom_read(common, off, data);

View File

@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
* Long slot time : 2x cwmin
* Short slot time : 4x cwmin
*/
if (ah->slottime == ATH9K_SLOT_TIME_20)
if (ah->slottime == 20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;

View File

@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->beacon.bslot[i] = NULL;
priv->beacon.slottime = ATH9K_SLOT_TIME_9;
priv->beacon.slottime = 9;
ath9k_cmn_init_channels_rates(common);
ath9k_cmn_init_crypto(ah);

View File

@ -454,7 +454,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
if (AR_SREV_9100(ah))
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
ah->slottime = ATH9K_SLOT_TIME_9;
ah->slottime = 9;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true;
@ -471,33 +471,34 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
}
static int ath9k_hw_init_macaddr(struct ath_hw *ah)
static void ath9k_hw_init_macaddr(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u32 sum;
int i;
u16 eeval;
static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
sum = 0;
/* MAC address may already be loaded via ath9k_platform_data */
if (is_valid_ether_addr(common->macaddr))
return;
for (i = 0; i < 3; i++) {
eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]);
sum += eeval;
common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff;
}
if (!is_valid_ether_addr(common->macaddr)) {
ath_err(common,
"eeprom contains invalid mac address: %pM\n",
common->macaddr);
random_ether_addr(common->macaddr);
ath_err(common,
"random mac address will be used: %pM\n",
common->macaddr);
}
if (is_valid_ether_addr(common->macaddr))
return;
return 0;
ath_err(common, "eeprom contains invalid mac address: %pM\n",
common->macaddr);
random_ether_addr(common->macaddr);
ath_err(common, "random mac address will be used: %pM\n",
common->macaddr);
return;
}
static int ath9k_hw_post_init(struct ath_hw *ah)
@ -636,12 +637,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (r)
return r;
r = ath9k_hw_init_macaddr(ah);
if (r) {
ath_err(common, "Failed to initialize MAC address\n");
return r;
}
ath9k_hw_init_macaddr(ah);
ath9k_hw_init_hang_checks(ah);
common->state = ATH_HW_INITIALIZED;
@ -1832,8 +1828,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 saveLedState;
u32 saveDefAntenna;
u32 macStaId1;
struct timespec tsf_ts;
u32 tsf_offset;
u64 tsf = 0;
s64 usec = 0;
int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@ -1877,8 +1874,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
/* Save TSF before chip reset, a cold reset clears it */
getrawmonotonic(&tsf_ts);
tsf = ath9k_hw_gettsf64(ah);
usec = ktime_to_us(ktime_get_raw());
saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@ -1911,8 +1908,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
/* Restore TSF */
usec = ktime_to_us(ktime_get_raw()) - usec;
ath9k_hw_settsf64(ah, tsf + usec);
tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
ath9k_hw_settsf64(ah, tsf + tsf_offset);
if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
@ -1932,12 +1929,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
/*
* Some AR91xx SoC devices frequently fail to accept TSF writes
* right after the chip reset. When that happens, write a new
* value after the initvals have been applied, with an offset
* based on measured time difference
* value after the initvals have been applied.
*/
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
tsf += 1500;
ath9k_hw_settsf64(ah, tsf);
tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
ath9k_hw_settsf64(ah, tsf + tsf_offset);
}
ath9k_hw_init_mfp(ah);

View File

@ -830,6 +830,7 @@ struct ath_hw {
/* Calibration */
u32 supp_cals;
struct ath9k_cal_list iq_caldata;
struct ath9k_cal_list temp_caldata;
struct ath9k_cal_list adcgain_caldata;
struct ath9k_cal_list adcdc_caldata;
struct ath9k_cal_list *cal_list;

View File

@ -372,7 +372,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
sc->beacon.slottime = 9;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
sc->beacon.bslot[i] = NULL;
@ -512,31 +512,52 @@ static void ath9k_eeprom_release(struct ath_softc *sc)
release_firmware(sc->sc_ah->eeprom_blob);
}
static int ath9k_init_soc_platform(struct ath_softc *sc)
static int ath9k_init_platform(struct ath_softc *sc)
{
struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = sc->sc_ah;
int ret = 0;
struct ath_common *common = ath9k_hw_common(ah);
int ret;
if (!pdata)
return 0;
if (!pdata->use_eeprom) {
ah->ah_flags &= ~AH_USE_EEPROM;
ah->gpio_mask = pdata->gpio_mask;
ah->gpio_val = pdata->gpio_val;
ah->led_pin = pdata->led_pin;
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
ah->external_reset = pdata->external_reset;
ah->disable_2ghz = pdata->disable_2ghz;
ah->disable_5ghz = pdata->disable_5ghz;
if (!pdata->endian_check)
ah->ah_flags |= AH_NO_EEP_SWAP;
}
if (pdata->eeprom_name) {
ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
if (ret)
return ret;
}
if (pdata->led_active_high)
ah->config.led_active_high = true;
if (pdata->tx_gain_buffalo)
ah->config.tx_gain_buffalo = true;
return ret;
if (pdata->macaddr)
ether_addr_copy(common->macaddr, pdata->macaddr);
return 0;
}
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = NULL;
struct ath9k_hw_capabilities *pCap;
struct ath_common *common;
@ -550,6 +571,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->dev = sc->dev;
ah->hw = sc->hw;
ah->hw_version.devid = devid;
ah->ah_flags |= AH_USE_EEPROM;
ah->led_pin = -1;
ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.multi_read = ath9k_multi_ioread32;
ah->reg_ops.write = ath9k_iowrite32;
@ -569,22 +592,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (!ath9k_is_chanctx_enabled())
sc->cur_chan->hw_queue_base = 0;
if (!pdata || pdata->use_eeprom) {
ah->ah_flags |= AH_USE_EEPROM;
sc->sc_ah->led_pin = -1;
} else {
sc->sc_ah->gpio_mask = pdata->gpio_mask;
sc->sc_ah->gpio_val = pdata->gpio_val;
sc->sc_ah->led_pin = pdata->led_pin;
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
ah->external_reset = pdata->external_reset;
ah->disable_2ghz = pdata->disable_2ghz;
ah->disable_5ghz = pdata->disable_5ghz;
if (!pdata->endian_check)
ah->ah_flags |= AH_NO_EEP_SWAP;
}
common->ops = &ah->reg_ops;
common->bus_ops = bus_ops;
common->ps_ops = &ath9k_ps_ops;
@ -600,7 +607,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
*/
ath9k_init_pcoem_platform(sc);
ret = ath9k_init_soc_platform(sc);
ret = ath9k_init_platform(sc);
if (ret)
return ret;
@ -646,9 +653,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret)
goto err_hw;
if (pdata && pdata->macaddr)
memcpy(common->macaddr, pdata->macaddr, ETH_ALEN);
ret = ath9k_init_queues(sc);
if (ret)
goto err_queues;

View File

@ -65,10 +65,6 @@
#define INIT_SSH_RETRY 32
#define INIT_SLG_RETRY 32
#define ATH9K_SLOT_TIME_6 6
#define ATH9K_SLOT_TIME_9 9
#define ATH9K_SLOT_TIME_20 20
#define ATH9K_TXERR_XRETRY 0x01
#define ATH9K_TXERR_FILT 0x02
#define ATH9K_TXERR_FIFO 0x04

View File

@ -910,6 +910,22 @@ static bool ath9k_uses_beacons(int type)
}
}
static void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data,
struct ieee80211_vif *vif)
{
/* Use the first (configured) interface, but prefering AP interfaces. */
if (!iter_data->primary_beacon_vif) {
iter_data->primary_beacon_vif = vif;
} else {
if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP &&
vif->type == NL80211_IFTYPE_AP)
iter_data->primary_beacon_vif = vif;
}
iter_data->beacons = true;
iter_data->nbcnvifs += 1;
}
static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
u8 *mac, struct ieee80211_vif *vif)
{
@ -926,11 +942,13 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
}
if (!vif->bss_conf.use_short_slot)
iter_data->slottime = ATH9K_SLOT_TIME_20;
iter_data->slottime = 20;
switch (vif->type) {
case NL80211_IFTYPE_AP:
iter_data->naps++;
if (vif->bss_conf.enable_beacon)
ath9k_vif_iter_set_beacon(iter_data, vif);
break;
case NL80211_IFTYPE_STATION:
iter_data->nstations++;
@ -943,12 +961,12 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
case NL80211_IFTYPE_ADHOC:
iter_data->nadhocs++;
if (vif->bss_conf.enable_beacon)
iter_data->beacons = true;
ath9k_vif_iter_set_beacon(iter_data, vif);
break;
case NL80211_IFTYPE_MESH_POINT:
iter_data->nmeshes++;
if (vif->bss_conf.enable_beacon)
iter_data->beacons = true;
ath9k_vif_iter_set_beacon(iter_data, vif);
break;
case NL80211_IFTYPE_WDS:
iter_data->nwds++;
@ -999,7 +1017,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
*/
memset(iter_data, 0, sizeof(*iter_data));
eth_broadcast_addr(iter_data->mask);
iter_data->slottime = ATH9K_SLOT_TIME_9;
iter_data->slottime = 9;
list_for_each_entry(avp, &ctx->vifs, list)
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
@ -1061,7 +1079,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc)
ah->opmode = vif->type;
ah->imask &= ~ATH9K_INT_SWBA;
ah->imask &= ~ATH9K_INT_TSFOOR;
ah->slottime = ATH9K_SLOT_TIME_9;
ah->slottime = 9;
ath_hw_setbssidmask(common);
ath9k_hw_setopmode(ah);
@ -1081,7 +1099,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_vif_iter_data iter_data;
struct ath_beacon_config *cur_conf;
ath_chanctx_check_active(sc, ctx);
@ -1103,13 +1120,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath_hw_setbssidmask(common);
if (iter_data.naps > 0) {
cur_conf = &ctx->beacon;
ath9k_hw_set_tsfadjust(ah, true);
ah->opmode = NL80211_IFTYPE_AP;
if (cur_conf->enable_beacon)
iter_data.beacons = true;
} else {
ath9k_hw_set_tsfadjust(ah, false);
if (iter_data.beacons)
ath9k_beacon_ensure_primary_slot(sc);
if (iter_data.nmeshes)
ah->opmode = NL80211_IFTYPE_MESH_POINT;
@ -1134,7 +1150,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ctx->switch_after_beacon = true;
}
ah->imask &= ~ATH9K_INT_SWBA;
if (ah->opmode == NL80211_IFTYPE_STATION) {
bool changed = (iter_data.primary_sta != ctx->primary_sta);
@ -1151,16 +1166,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
if (ath9k_hw_mci_is_enabled(sc->sc_ah))
ath9k_mci_update_wlan_channels(sc, true);
}
} else if (iter_data.beacons) {
ah->imask |= ATH9K_INT_SWBA;
}
sc->nbcnvifs = iter_data.nbcnvifs;
ath9k_beacon_config(sc, iter_data.primary_beacon_vif,
iter_data.beacons);
ath9k_hw_set_interrupts(ah);
if (iter_data.beacons)
set_bit(ATH_OP_BEACONS, &common->op_flags);
else
clear_bit(ATH_OP_BEACONS, &common->op_flags);
if (ah->slottime != iter_data.slottime) {
ah->slottime = iter_data.slottime;
ath9k_hw_init_global_settings(ah);
@ -1777,9 +1788,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT) ||
(changed & BSS_CHANGED_BEACON_INFO)) {
ath9k_beacon_config(sc, vif, changed);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath9k_calculate_summary_state(sc, avp->chanctx);
ath9k_calculate_summary_state(sc, avp->chanctx);
}
if ((avp->chanctx == sc->cur_chan) &&
@ -1788,6 +1797,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
slottime = 9;
else
slottime = 20;
if (vif->type == NL80211_IFTYPE_AP) {
/*
* Defer update, so that connected stations can adjust
@ -1823,11 +1833,19 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
u64 tsf;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
tsf = ath9k_hw_gettsf64(sc->sc_ah);
/* Get current TSF either from HW or kernel time. */
if (sc->cur_chan == avp->chanctx) {
tsf = ath9k_hw_gettsf64(sc->sc_ah);
} else {
tsf = sc->cur_chan->tsf_val +
ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
}
tsf += le64_to_cpu(avp->tsf_adjust);
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
@ -1839,10 +1857,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
u64 tsf)
{
struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
ath9k_hw_settsf64(sc->sc_ah, tsf);
tsf -= le64_to_cpu(avp->tsf_adjust);
getrawmonotonic(&avp->chanctx->tsf_ts);
if (sc->cur_chan == avp->chanctx)
ath9k_hw_settsf64(sc->sc_ah, tsf);
avp->chanctx->tsf_val = tsf;
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
}
@ -1850,11 +1873,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
ath9k_hw_reset_tsf(sc->sc_ah);
getrawmonotonic(&avp->chanctx->tsf_ts);
if (sc->cur_chan == avp->chanctx)
ath9k_hw_reset_tsf(sc->sc_ah);
avp->chanctx->tsf_val = 0;
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);

View File

@ -19,7 +19,6 @@
#include <linux/nl80211.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h>
#include "ath9k.h"
@ -786,35 +785,21 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
struct ath_softc *sc = (struct ath_softc *) common->priv;
struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = (struct ath_hw *) common->ah;
if (pdata && !pdata->use_eeprom) {
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
ath_err(common,
"%s: eeprom read failed, offset %08x is out of range\n",
__func__, off);
}
common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
*data = pdata->eeprom_data[off];
} else {
struct ath_hw *ah = (struct ath_hw *) common->ah;
common->ops->read(ah, AR5416_EEPROM_OFFSET +
(off << AR5416_EEPROM_S));
if (!ath9k_hw_wait(ah,
AR_EEPROM_STATUS_DATA,
AR_EEPROM_STATUS_DATA_BUSY |
AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
AH_WAIT_TIMEOUT)) {
return false;
}
*data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
AR_EEPROM_STATUS_DATA_VAL);
if (!ath9k_hw_wait(ah,
AR_EEPROM_STATUS_DATA,
AR_EEPROM_STATUS_DATA_BUSY |
AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
AH_WAIT_TIMEOUT)) {
return false;
}
*data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
AR_EEPROM_STATUS_DATA_VAL);
return true;
}

View File

@ -35,26 +35,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
return ch->head_blk_ctl->bd_cpu_addr;
}
static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
{
wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_ccu_write_register: addr=%x, data=%x\n",
addr, data);
writel(data, wcn->ccu_base + addr);
}
static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
{
wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_write_register: addr=%x, data=%x\n",
addr, data);
writel(data, wcn->mmio + addr);
writel(data, wcn->dxe_base + addr);
}
#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data) \
do { \
if (wcn->chip_version == WCN36XX_CHIP_3680) \
wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
else \
wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
} while (0) \
static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
{
*data = readl(wcn->mmio + addr);
*data = readl(wcn->dxe_base + addr);
wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_read_register: addr=%x, data=%x\n",
@ -701,9 +702,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
reg_data = WCN36XX_DXE_REG_RESET;
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
/* Setting interrupt path */
reg_data = WCN36XX_DXE_CCU_INT;
wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
/* Select channels for rx avail and xfer done interrupts... */
reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
if (wcn->is_pronto)
wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
else
wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
/***************************************/
/* Init descriptors for TX LOW channel */

View File

@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2
*/
/* DXE registers */
#define WCN36XX_DXE_MEM_REG 0x202000
#define WCN36XX_DXE_MEM_REG 0
#define WCN36XX_DXE_CCU_INT 0xA0011
#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10
#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
/* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44

View File

@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req {
/* Update scan params - sent from host to PNO to be used during PNO
* scanningx */
struct update_scan_params_req_ex {
struct wcn36xx_hal_update_scan_params_req_ex {
struct wcn36xx_hal_msg_header header;
@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex {
/* Cb State */
enum phy_chan_bond_state state;
};
} __packed;
/* Update scan params - sent from host to PNO to be used during PNO
* scanningx */

View File

@ -19,6 +19,8 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask;
@ -259,17 +261,6 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
}
}
static void wcn36xx_detect_chip_version(struct wcn36xx *wcn)
{
if (get_feat_caps(wcn->fw_feat_caps, DOT11AC)) {
wcn36xx_info("Chip is 3680\n");
wcn->chip_version = WCN36XX_CHIP_3680;
} else {
wcn36xx_info("Chip is 3660\n");
wcn->chip_version = WCN36XX_CHIP_3660;
}
}
static int wcn36xx_start(struct ieee80211_hw *hw)
{
struct wcn36xx *wcn = hw->priv;
@ -324,9 +315,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_feat_caps_info(wcn);
}
wcn36xx_detect_chip_version(wcn);
wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
/* DMA channel initialization */
ret = wcn36xx_dxe_init(wcn);
if (ret) {
@ -1064,7 +1052,11 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
struct platform_device *pdev)
{
struct device_node *mmio_node;
struct resource *res;
int index;
int ret;
/* Set TX IRQ */
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"wcnss_wlantx_irq");
@ -1083,19 +1075,40 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
}
wcn->rx_irq = res->start;
/* Map the memory */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"wcnss_mmio");
if (!res) {
wcn36xx_err("failed to get mmio\n");
return -ENOENT;
mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
if (!mmio_node) {
wcn36xx_err("failed to acquire qcom,mmio reference\n");
return -EINVAL;
}
wcn->mmio = ioremap(res->start, resource_size(res));
if (!wcn->mmio) {
wcn36xx_err("failed to map io memory\n");
return -ENOMEM;
wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
/* Map the CCU memory */
index = of_property_match_string(mmio_node, "reg-names", "ccu");
wcn->ccu_base = of_iomap(mmio_node, index);
if (!wcn->ccu_base) {
wcn36xx_err("failed to map ccu memory\n");
ret = -ENOMEM;
goto put_mmio_node;
}
/* Map the DXE memory */
index = of_property_match_string(mmio_node, "reg-names", "dxe");
wcn->dxe_base = of_iomap(mmio_node, index);
if (!wcn->dxe_base) {
wcn36xx_err("failed to map dxe memory\n");
ret = -ENOMEM;
goto unmap_ccu;
}
of_node_put(mmio_node);
return 0;
unmap_ccu:
iounmap(wcn->ccu_base);
put_mmio_node:
of_node_put(mmio_node);
return ret;
}
static int wcn36xx_probe(struct platform_device *pdev)
@ -1138,7 +1151,8 @@ static int wcn36xx_probe(struct platform_device *pdev)
return 0;
out_unmap:
iounmap(wcn->mmio);
iounmap(wcn->ccu_base);
iounmap(wcn->dxe_base);
out_wq:
ieee80211_free_hw(hw);
out_err:
@ -1154,7 +1168,8 @@ static int wcn36xx_remove(struct platform_device *pdev)
mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw);
iounmap(wcn->mmio);
iounmap(wcn->dxe_base);
iounmap(wcn->ccu_base);
ieee80211_free_hw(hw);
return 0;

View File

@ -674,22 +674,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
return 0;
}
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,
u8 *channels, size_t channel_count)
{
struct wcn36xx_hal_update_scan_params_req msg_body;
struct wcn36xx_hal_update_scan_params_req_ex msg_body;
int ret = 0;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
msg_body.dot11d_enabled = 0;
msg_body.dot11d_resolved = 0;
msg_body.channel_count = 26;
msg_body.dot11d_enabled = false;
msg_body.dot11d_resolved = true;
msg_body.channel_count = channel_count;
memcpy(msg_body.channels, channels, channel_count);
msg_body.active_min_ch_time = 60;
msg_body.active_max_ch_time = 120;
msg_body.passive_min_ch_time = 60;
msg_body.passive_max_ch_time = 110;
msg_body.state = 0;
msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
@ -2226,17 +2229,12 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
if (!msg_ind)
goto nomem;
msg_ind->msg_len = len;
msg_ind->msg = kmemdup(buf, len, GFP_KERNEL);
if (!msg_ind->msg) {
kfree(msg_ind);
nomem:
msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
if (!msg_ind) {
/*
* FIXME: Do something smarter then just
* printing an error.
@ -2245,10 +2243,14 @@ nomem:
msg_header->msg_type);
break;
}
mutex_lock(&wcn->hal_ind_mutex);
msg_ind->msg_len = len;
memcpy(msg_ind->msg, buf, len);
spin_lock(&wcn->hal_ind_lock);
list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
mutex_unlock(&wcn->hal_ind_mutex);
spin_unlock(&wcn->hal_ind_lock);
wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
break;
default:
@ -2262,8 +2264,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
container_of(work, struct wcn36xx, hal_ind_work);
struct wcn36xx_hal_msg_header *msg_header;
struct wcn36xx_hal_ind_msg *hal_ind_msg;
unsigned long flags;
mutex_lock(&wcn->hal_ind_mutex);
spin_lock_irqsave(&wcn->hal_ind_lock, flags);
hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
struct wcn36xx_hal_ind_msg,
@ -2273,6 +2276,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
switch (msg_header->msg_type) {
case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
break;
case WCN36XX_HAL_OTA_TX_COMPL_IND:
@ -2295,9 +2299,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
msg_header->msg_type);
}
list_del(wcn->hal_ind_queue.next);
kfree(hal_ind_msg->msg);
spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
kfree(hal_ind_msg);
mutex_unlock(&wcn->hal_ind_mutex);
}
int wcn36xx_smd_open(struct wcn36xx *wcn)
{
@ -2310,7 +2313,7 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
}
INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
INIT_LIST_HEAD(&wcn->hal_ind_queue);
mutex_init(&wcn->hal_ind_mutex);
spin_lock_init(&wcn->hal_ind_lock);
ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
if (ret) {
@ -2330,5 +2333,4 @@ void wcn36xx_smd_close(struct wcn36xx *wcn)
{
wcn->ctrl_ops->close();
destroy_workqueue(wcn->hal_ind_wq);
mutex_destroy(&wcn->hal_ind_mutex);
}

View File

@ -46,8 +46,8 @@ struct wcn36xx_fw_msg_status_rsp {
struct wcn36xx_hal_ind_msg {
struct list_head list;
u8 *msg;
size_t msg_len;
u8 msg[];
};
struct wcn36xx;
@ -63,7 +63,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
enum wcn36xx_hal_sys_mode mode);
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);

View File

@ -193,7 +193,7 @@ struct wcn36xx {
u8 fw_minor;
u8 fw_major;
u32 fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
u32 chip_version;
bool is_pronto;
/* extra byte for the NULL termination */
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
@ -202,7 +202,8 @@ struct wcn36xx {
/* IRQs */
int tx_irq;
int rx_irq;
void __iomem *mmio;
void __iomem *ccu_base;
void __iomem *dxe_base;
struct wcn36xx_platform_ctrl_ops *ctrl_ops;
/*
@ -215,7 +216,7 @@ struct wcn36xx {
struct completion hal_rsp_compl;
struct workqueue_struct *hal_ind_wq;
struct work_struct hal_ind_work;
struct mutex hal_ind_mutex;
spinlock_t hal_ind_lock;
struct list_head hal_ind_queue;
/* DXE channels */
@ -241,9 +242,6 @@ struct wcn36xx {
};
#define WCN36XX_CHIP_3660 0
#define WCN36XX_CHIP_3680 1
static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
u8 major,
u8 minor,

View File

@ -726,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
return -ENOMEM;
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
glom_skb);
if (err)
if (err) {
brcmu_pkt_buf_free_skb(glom_skb);
goto done;
}
skb_queue_walk(pktq, skb) {
memcpy(skb->data, glom_skb->data, skb->len);

View File

@ -4666,6 +4666,15 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("SET SSID error (%d)\n", err);
goto exit;
}
if (settings->hidden_ssid) {
err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
if (err) {
brcmf_err("closednet error (%d)\n", err);
goto exit;
}
}
brcmf_dbg(TRACE, "AP mode configuration complete\n");
} else if (dev_role == NL80211_IFTYPE_P2P_GO) {
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
@ -4724,6 +4733,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
return err;
}
/* First BSS doesn't get a full reset */
if (ifp->bsscfgidx == 0)
brcmf_fil_iovar_int_set(ifp, "closednet", 0);
memset(&join_params, 0, sizeof(join_params));
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params));

View File

@ -2469,10 +2469,22 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
{
struct brcmf_fws_info *fws = drvr->fws;
struct brcmf_if *ifp;
int i;
fws->bus_flow_blocked = flow_blocked;
if (!flow_blocked)
brcmf_fws_schedule_deq(fws);
else
fws->stats.bus_flow_block++;
if (fws->avoid_queueing) {
for (i = 0; i < BRCMF_MAX_IFS; i++) {
ifp = drvr->iflist[i];
if (!ifp || !ifp->ndev)
continue;
brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
flow_blocked);
}
} else {
fws->bus_flow_blocked = flow_blocked;
if (!flow_blocked)
brcmf_fws_schedule_deq(fws);
else
fws->stats.bus_flow_block++;
}
}

View File

@ -3305,10 +3305,6 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
goto err;
}
/* Allow full data communication using DPC from now on. */
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
bcmerror = 0;
err:
brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
sdio_release_host(bus->sdiodev->func[1]);
@ -4046,6 +4042,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
}
if (err == 0) {
/* Allow full data communication using DPC from now on. */
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
err = brcmf_sdiod_intr_register(sdiodev);
if (err != 0)
brcmf_err("intr register failed:%d\n", err);

View File

@ -1079,8 +1079,10 @@ bool dma_rxfill(struct dma_pub *pub)
pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
DMA_FROM_DEVICE);
if (dma_mapping_error(di->dmadev, pa))
if (dma_mapping_error(di->dmadev, pa)) {
brcmu_pkt_buf_free_skb(p);
return false;
}
/* save the free packet pointer */
di->rxp[rxout] = p;

View File

@ -87,7 +87,7 @@ void
brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
u16 chanspec)
{
struct tx_power power;
struct tx_power power = { };
u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
/* Clear previous settings */

View File

@ -73,8 +73,8 @@
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 17
#define IWL7265_UCODE_API_MAX 17
#define IWL7265D_UCODE_API_MAX 21
#define IWL3168_UCODE_API_MAX 21
#define IWL7265D_UCODE_API_MAX 24
#define IWL3168_UCODE_API_MAX 24
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 16

View File

@ -70,8 +70,8 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 21
#define IWL8265_UCODE_API_MAX 21
#define IWL8000_UCODE_API_MAX 24
#define IWL8265_UCODE_API_MAX 24
/* Lowest firmware API version supported */
#define IWL8000_UCODE_API_MIN 16

View File

@ -55,7 +55,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 21
#define IWL9000_UCODE_API_MAX 24
/* Lowest firmware API version supported */
#define IWL9000_UCODE_API_MIN 16

View File

@ -2044,8 +2044,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout)
static int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout)
{
struct lbs_private *priv = wiphy_priv(wiphy);

View File

@ -1936,10 +1936,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_uap_rates(bss_cfg, params);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
mwifiex_dbg(priv->adapter, ERROR,
"Failed to parse secuirty parameters!\n");
return -1;
goto out;
}
mwifiex_set_ht_params(priv, bss_cfg, params);
@ -1968,7 +1967,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
if (mwifiex_11h_activate(priv, false)) {
mwifiex_dbg(priv->adapter, ERROR,
"Failed to disable 11h extensions!!");
return -1;
goto out;
}
priv->state_11h.is_11h_active = false;
}
@ -1976,12 +1975,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
if (mwifiex_config_start_uap(priv, bss_cfg)) {
mwifiex_dbg(priv->adapter, ERROR,
"Failed to start AP\n");
kfree(bss_cfg);
return -1;
goto out;
}
if (mwifiex_set_mgmt_ies(priv, &params->beacon))
return -1;
goto out;
if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(priv->netdev);
@ -1990,6 +1988,10 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg));
kfree(bss_cfg);
return 0;
out:
kfree(bss_cfg);
return -1;
}
/*

View File

@ -343,16 +343,16 @@ enum {
};
struct mwifiex_ds_reg_rw {
__le32 type;
__le32 offset;
__le32 value;
u32 type;
u32 offset;
u32 value;
};
#define MAX_EEPROM_DATA 256
struct mwifiex_ds_read_eeprom {
__le16 offset;
__le16 byte_count;
u16 offset;
u16 byte_count;
u8 value[MAX_EEPROM_DATA];
};

View File

@ -202,7 +202,6 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__);
kfree(card);
return -1;
}
@ -1617,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
pkt_len = *((__le16 *)skb->data);
rx_len = le16_to_cpu(pkt_len);
skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
skb_trim(skb, rx_len);
skb_pull(skb, INTF_HEADER_LEN);
@ -2301,6 +2301,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
}
}
if (!card->msi_enable) {
spin_lock_irqsave(&adapter->int_lock, flags);
pcie_ireg |= adapter->int_status;
adapter->int_status = 0;
spin_unlock_irqrestore(&adapter->int_lock, flags);
}
}
mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n",
@ -2843,7 +2849,6 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
"MRVL_PCIE", &card->share_irq_ctx);
if (ret) {
pr_err("request_irq failed: ret=%d\n", ret);
adapter->card = NULL;
return -1;
}

View File

@ -1148,9 +1148,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
mac_reg = &cmd->params.mac_reg;
mac_reg->action = cpu_to_le16(cmd_action);
mac_reg->offset =
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
mac_reg->value = reg_rw->value;
mac_reg->offset = cpu_to_le16((u16) reg_rw->offset);
mac_reg->value = cpu_to_le32(reg_rw->value);
break;
}
case HostCmd_CMD_BBP_REG_ACCESS:
@ -1160,9 +1159,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
bbp_reg = &cmd->params.bbp_reg;
bbp_reg->action = cpu_to_le16(cmd_action);
bbp_reg->offset =
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
bbp_reg->offset = cpu_to_le16((u16) reg_rw->offset);
bbp_reg->value = (u8) reg_rw->value;
break;
}
case HostCmd_CMD_RF_REG_ACCESS:
@ -1172,8 +1170,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
rf_reg = &cmd->params.rf_reg;
rf_reg->action = cpu_to_le16(cmd_action);
rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
rf_reg->offset = cpu_to_le16((u16) reg_rw->offset);
rf_reg->value = (u8) reg_rw->value;
break;
}
case HostCmd_CMD_PMIC_REG_ACCESS:
@ -1183,9 +1181,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
pmic_reg = &cmd->params.pmic_reg;
pmic_reg->action = cpu_to_le16(cmd_action);
pmic_reg->offset =
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
pmic_reg->offset = cpu_to_le16((u16) reg_rw->offset);
pmic_reg->value = (u8) reg_rw->value;
break;
}
case HostCmd_CMD_CAU_REG_ACCESS:
@ -1195,9 +1192,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
cau_reg = &cmd->params.rf_reg;
cau_reg->action = cpu_to_le16(cmd_action);
cau_reg->offset =
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
cau_reg->offset = cpu_to_le16((u16) reg_rw->offset);
cau_reg->value = (u8) reg_rw->value;
break;
}
case HostCmd_CMD_802_11_EEPROM_ACCESS:
@ -1208,8 +1204,8 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
cmd_eeprom->action = cpu_to_le16(cmd_action);
cmd_eeprom->offset = rd_eeprom->offset;
cmd_eeprom->byte_count = rd_eeprom->byte_count;
cmd_eeprom->offset = cpu_to_le16(rd_eeprom->offset);
cmd_eeprom->byte_count = cpu_to_le16(rd_eeprom->byte_count);
cmd_eeprom->value = 0;
break;
}

View File

@ -786,45 +786,44 @@ static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
switch (type) {
case HostCmd_CMD_MAC_REG_ACCESS:
r.mac = &resp->params.mac_reg;
reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.mac->offset));
reg_rw->value = r.mac->value;
reg_rw->offset = (u32) le16_to_cpu(r.mac->offset);
reg_rw->value = le32_to_cpu(r.mac->value);
break;
case HostCmd_CMD_BBP_REG_ACCESS:
r.bbp = &resp->params.bbp_reg;
reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.bbp->offset));
reg_rw->value = cpu_to_le32((u32) r.bbp->value);
reg_rw->offset = (u32) le16_to_cpu(r.bbp->offset);
reg_rw->value = (u32) r.bbp->value;
break;
case HostCmd_CMD_RF_REG_ACCESS:
r.rf = &resp->params.rf_reg;
reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset));
reg_rw->value = cpu_to_le32((u32) r.bbp->value);
reg_rw->offset = (u32) le16_to_cpu(r.rf->offset);
reg_rw->value = (u32) r.bbp->value;
break;
case HostCmd_CMD_PMIC_REG_ACCESS:
r.pmic = &resp->params.pmic_reg;
reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.pmic->offset));
reg_rw->value = cpu_to_le32((u32) r.pmic->value);
reg_rw->offset = (u32) le16_to_cpu(r.pmic->offset);
reg_rw->value = (u32) r.pmic->value;
break;
case HostCmd_CMD_CAU_REG_ACCESS:
r.rf = &resp->params.rf_reg;
reg_rw->offset = cpu_to_le32((u32) le16_to_cpu(r.rf->offset));
reg_rw->value = cpu_to_le32((u32) r.rf->value);
reg_rw->offset = (u32) le16_to_cpu(r.rf->offset);
reg_rw->value = (u32) r.rf->value;
break;
case HostCmd_CMD_802_11_EEPROM_ACCESS:
r.eeprom = &resp->params.eeprom;
pr_debug("info: EEPROM read len=%x\n", r.eeprom->byte_count);
if (le16_to_cpu(eeprom->byte_count) <
le16_to_cpu(r.eeprom->byte_count)) {
eeprom->byte_count = cpu_to_le16(0);
pr_debug("info: EEPROM read len=%x\n",
le16_to_cpu(r.eeprom->byte_count));
if (eeprom->byte_count < le16_to_cpu(r.eeprom->byte_count)) {
eeprom->byte_count = 0;
pr_debug("info: EEPROM read length is too big\n");
return -1;
}
eeprom->offset = r.eeprom->offset;
eeprom->byte_count = r.eeprom->byte_count;
if (le16_to_cpu(eeprom->byte_count) > 0)
eeprom->offset = le16_to_cpu(r.eeprom->offset);
eeprom->byte_count = le16_to_cpu(r.eeprom->byte_count);
if (eeprom->byte_count > 0)
memcpy(&eeprom->value, &r.eeprom->value,
le16_to_cpu(r.eeprom->byte_count));
min((u16)MAX_EEPROM_DATA, eeprom->byte_count));
break;
default:
return -1;

View File

@ -1251,7 +1251,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
{
u16 cmd_no;
switch (le32_to_cpu(reg_rw->type)) {
switch (reg_rw->type) {
case MWIFIEX_REG_MAC:
cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
break;
@ -1286,9 +1286,9 @@ mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
{
struct mwifiex_ds_reg_rw reg_rw;
reg_rw.type = cpu_to_le32(reg_type);
reg_rw.offset = cpu_to_le32(reg_offset);
reg_rw.value = cpu_to_le32(reg_value);
reg_rw.type = reg_type;
reg_rw.offset = reg_offset;
reg_rw.value = reg_value;
return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);
}
@ -1306,14 +1306,14 @@ mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
int ret;
struct mwifiex_ds_reg_rw reg_rw;
reg_rw.type = cpu_to_le32(reg_type);
reg_rw.offset = cpu_to_le32(reg_offset);
reg_rw.type = reg_type;
reg_rw.offset = reg_offset;
ret = mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_GET);
if (ret)
goto done;
*value = le32_to_cpu(reg_rw.value);
*value = reg_rw.value;
done:
return ret;
@ -1332,15 +1332,16 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
int ret;
struct mwifiex_ds_read_eeprom rd_eeprom;
rd_eeprom.offset = cpu_to_le16((u16) offset);
rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
rd_eeprom.offset = offset;
rd_eeprom.byte_count = bytes;
/* Send request to firmware */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);
if (!ret)
memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,
rd_eeprom.byte_count));
return ret;
}

View File

@ -12,4 +12,4 @@ rtl8188ee-objs := \
obj-$(CONFIG_RTL8188EE) += rtl8188ee.o
ccflags-y += -Idrivers/net/wireless/rtlwifi -D__CHECK_ENDIAN__
ccflags-y += -D__CHECK_ENDIAN__

View File

@ -1214,6 +1214,10 @@ static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
int_fw_status->counters.tx_voice_released_blks;
fw_status->counters.tx_last_rate =
int_fw_status->counters.tx_last_rate;
fw_status->counters.tx_last_rate_mbps =
int_fw_status->counters.tx_last_rate_mbps;
fw_status->counters.hlid =
int_fw_status->counters.hlid;
fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
@ -1821,9 +1825,12 @@ static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
},
{
.max = 1,
.types = BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT),
.types = BIT(NL80211_IFTYPE_AP)
| BIT(NL80211_IFTYPE_P2P_GO)
| BIT(NL80211_IFTYPE_P2P_CLIENT)
#ifdef CONFIG_MAC80211_MESH
| BIT(NL80211_IFTYPE_MESH_POINT)
#endif
},
{
.max = 1,
@ -1836,6 +1843,12 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
.max = 2,
.types = BIT(NL80211_IFTYPE_AP),
},
#ifdef CONFIG_MAC80211_MESH
{
.max = 1,
.types = BIT(NL80211_IFTYPE_MESH_POINT),
},
#endif
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE),

View File

@ -30,9 +30,9 @@
static
void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
u8 band, struct ieee80211_tx_rate *rate)
u8 band, struct ieee80211_tx_rate *rate, u8 hlid)
{
u8 fw_rate = wl->fw_status->counters.tx_last_rate;
u8 fw_rate = wl->links[hlid].fw_rate_idx;
if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
wl1271_error("last Tx rate invalid: %d", fw_rate);
@ -79,6 +79,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
struct sk_buff *skb;
int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
bool tx_success;
struct wl1271_tx_hw_descr *tx_desc;
/* check for id legality */
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
@ -91,6 +92,7 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
tx_desc = (struct wl1271_tx_hw_descr *)skb->data;
if (wl12xx_is_dummy_packet(wl, skb)) {
wl1271_free_tx_id(wl, id);
@ -105,7 +107,9 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
* the info->status structures
*/
wl18xx_get_last_tx_rate(wl, info->control.vif,
info->band, &info->status.rates[0]);
info->band,
&info->status.rates[0],
tx_desc->hlid);
info->status.rates[0].count = 1; /* no data about retries */
info->status.ack_signal = -1;
@ -144,12 +148,22 @@ void wl18xx_tx_immediate_complete(struct wl1271 *wl)
struct wl18xx_fw_status_priv *status_priv =
(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
struct wl18xx_priv *priv = wl->priv;
u8 i;
u8 i, hlid;
/* nothing to do here */
if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
return;
/* update rates per link */
hlid = wl->fw_status->counters.hlid;
if (hlid < WLCORE_MAX_LINKS) {
wl->links[hlid].fw_rate_idx =
wl->fw_status->counters.tx_last_rate;
wl->links[hlid].fw_rate_mbps =
wl->fw_status->counters.tx_last_rate_mbps;
}
/* freed Tx descriptors */
wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
priv->last_fw_rls_idx, status_priv->fw_release_idx);

View File

@ -29,7 +29,7 @@
#define WL18XX_IFTYPE_VER 9
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
#define WL18XX_MINOR_VER 11
#define WL18XX_MINOR_VER 58
#define WL18XX_CMD_MAX_SIZE 740
@ -125,7 +125,11 @@ struct wl18xx_fw_packet_counters {
/* Tx rate of the last transmitted packet */
u8 tx_last_rate;
u8 padding[2];
/* Tx rate or Tx rate estimate pre-calculated by fw in mbps units */
u8 tx_last_rate_mbps;
/* hlid for which the rates were reported */
u8 hlid;
} __packed;
/* FW status registers */

View File

@ -105,6 +105,7 @@ enum wl12xx_role {
WL1271_ROLE_DEVICE,
WL1271_ROLE_P2P_CL,
WL1271_ROLE_P2P_GO,
WL1271_ROLE_MESH_POINT,
WL12XX_INVALID_ROLE_TYPE = 0xff
};

View File

@ -130,7 +130,7 @@ fail:
wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
"Please use at least FW %s\n"
"You can get the latest firmwares at:\n"
"git://github.com/TI-OpenLink/firmwares.git",
"git://git.ti.com/wilink8-wlan/wl18xx_fw.git",
fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
fw_ver[FW_VER_MINOR], min_fw_str);

View File

@ -629,11 +629,14 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
/* trying to use hidden SSID with an old hostapd version */
if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
wl1271_error("got a null SSID from beacon/bss");
ret = -EINVAL;
goto out;
/* If MESH --> ssid_len is always 0 */
if (!ieee80211_vif_is_mesh(vif)) {
/* trying to use hidden SSID with an old hostapd version */
if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
wl1271_error("got a null SSID from beacon/bss");
ret = -EINVAL;
goto out;
}
}
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);

View File

@ -221,6 +221,7 @@ static void wlcore_rc_update_work(struct work_struct *work)
struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
rc_update_work);
struct wl1271 *wl = wlvif->wl;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
mutex_lock(&wl->mutex);
@ -231,8 +232,16 @@ static void wlcore_rc_update_work(struct work_struct *work)
if (ret < 0)
goto out;
wlcore_hw_sta_rc_update(wl, wlvif);
if (ieee80211_vif_is_mesh(vif)) {
ret = wl1271_acx_set_ht_capabilities(wl, &wlvif->rc_ht_cap,
true, wlvif->sta.hlid);
if (ret < 0)
goto out_sleep;
} else {
wlcore_hw_sta_rc_update(wl, wlvif);
}
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
@ -2153,10 +2162,14 @@ static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx)
static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
switch (wlvif->bss_type) {
case BSS_TYPE_AP_BSS:
if (wlvif->p2p)
return WL1271_ROLE_P2P_GO;
else if (ieee80211_vif_is_mesh(vif))
return WL1271_ROLE_MESH_POINT;
else
return WL1271_ROLE_AP;
@ -2198,6 +2211,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wlvif->p2p = 1;
/* fall-through */
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
wlvif->bss_type = BSS_TYPE_AP_BSS;
break;
default:
@ -4131,9 +4145,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if (ret < 0)
goto out;
ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
if (ret < 0)
goto out;
/* No need to set probe resp template for mesh */
if (!ieee80211_vif_is_mesh(vif)) {
ret = wl1271_ap_set_probe_resp_tmpl(wl,
wlvif->basic_rate,
vif);
if (ret < 0)
goto out;
}
ret = wlcore_set_beacon_template(wl, vif, true);
if (ret < 0)
@ -4967,6 +4986,7 @@ static int wl12xx_sta_add(struct wl1271 *wl,
return ret;
wl_sta = (struct wl1271_station *)sta->drv_priv;
wl_sta->wl = wl;
hlid = wl_sta->hlid;
ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
@ -5641,6 +5661,7 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
/* this callback is atomic, so schedule a new work */
wlvif->rc_update_bw = sta->bandwidth;
memcpy(&wlvif->rc_ht_cap, &sta->ht_cap, sizeof(sta->ht_cap));
ieee80211_queue_work(hw, &wlvif->rc_update_work);
}
@ -5679,6 +5700,16 @@ out:
mutex_unlock(&wl->mutex);
}
static u32 wlcore_op_get_expected_throughput(struct ieee80211_sta *sta)
{
struct wl1271_station *wl_sta = (struct wl1271_station *)sta->drv_priv;
struct wl1271 *wl = wl_sta->wl;
u8 hlid = wl_sta->hlid;
/* return in units of Kbps */
return (wl->links[hlid].fw_rate_mbps * 1000);
}
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@ -5879,6 +5910,7 @@ static const struct ieee80211_ops wl1271_ops = {
.switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
.sta_statistics = wlcore_op_sta_statistics,
.get_expected_throughput = wlcore_op_get_expected_throughput,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@ -6062,7 +6094,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_P2P_GO);
wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->max_sched_scan_ssids = 16;
wl->hw->wiphy->max_match_sets = 16;

View File

@ -222,6 +222,13 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status)
enum wl_rx_buf_align rx_align;
int ret = 0;
/* update rates per link */
hlid = status->counters.hlid;
if (hlid < WLCORE_MAX_LINKS)
wl->links[hlid].fw_rate_mbps =
status->counters.tx_last_rate_mbps;
while (drv_rx_counter != fw_rx_counter) {
buf_size = 0;
rx_counter = drv_rx_counter;

View File

@ -70,16 +70,30 @@
#define WSPI_MAX_CHUNK_SIZE 4092
/*
* only support SPI for 12xx - this code should be reworked when 18xx
* support is introduced
* wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to
* (4 * PAGE_SIZE) for wl12xx, so use the larger buffer needed for wl18xx
*/
#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
#define SPI_AGGR_BUFFER_SIZE (13 * PAGE_SIZE)
/* Maximum number of SPI write chunks */
#define WSPI_MAX_NUM_OF_CHUNKS \
((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1)
struct wilink_familiy_data {
char name[8];
};
const struct wilink_familiy_data *wilink_data;
static const struct wilink_familiy_data wl18xx_data = {
.name = "wl18xx",
};
static const struct wilink_familiy_data wl12xx_data = {
.name = "wl12xx",
};
struct wl12xx_spi_glue {
struct device *dev;
struct platform_device *core;
@ -119,6 +133,7 @@ static void wl12xx_spi_init(struct device *child)
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct spi_transfer t;
struct spi_message m;
struct spi_device *spi = to_spi_device(glue->dev);
u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
@ -151,6 +166,7 @@ static void wl12xx_spi_init(struct device *child)
cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END;
/*
* The above is the logical order; it must actually be stored
* in the buffer byte-swapped.
@ -163,6 +179,28 @@ static void wl12xx_spi_init(struct device *child)
spi_message_add_tail(&t, &m);
spi_sync(to_spi_device(glue->dev), &m);
/* Send extra clocks with inverted CS (high). this is required
* by the wilink family in order to successfully enter WSPI mode.
*/
spi->mode ^= SPI_CS_HIGH;
memset(&m, 0, sizeof(m));
spi_message_init(&m);
cmd[0] = 0xff;
cmd[1] = 0xff;
cmd[2] = 0xff;
cmd[3] = 0xff;
__swab32s((u32 *)cmd);
t.tx_buf = cmd;
t.len = 4;
spi_message_add_tail(&t, &m);
spi_sync(to_spi_device(glue->dev), &m);
/* Restore chip select configration to normal */
spi->mode ^= SPI_CS_HIGH;
kfree(cmd);
}
@ -270,22 +308,25 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
return 0;
}
static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
static int __wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
/* SPI write buffers - 2 for each chunk */
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_transfer *t;
struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */
u32 *cmd;
u32 chunk_len;
int i;
/* SPI write buffers - 2 for each chunk */
t = kzalloc(sizeof(*t) * 2 * WSPI_MAX_NUM_OF_CHUNKS, GFP_KERNEL);
if (!t)
return -ENOMEM;
WARN_ON(len > SPI_AGGR_BUFFER_SIZE);
spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd = &commands[0];
i = 0;
@ -318,9 +359,26 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
spi_sync(to_spi_device(glue->dev), &m);
kfree(t);
return 0;
}
static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
int ret;
/* The ELP wakeup write may fail the first time due to internal
* hardware latency. It is safer to send the wakeup command twice to
* avoid unexpected failures.
*/
if (addr == HW_ACCESS_ELP_CTRL_REG)
ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed);
ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed);
return ret;
}
/**
* wl12xx_spi_set_power - power on/off the wl12xx unit
* @child: wl12xx device handle.
@ -349,17 +407,38 @@ static int wl12xx_spi_set_power(struct device *child, bool enable)
return ret;
}
/**
* wl12xx_spi_set_block_size
*
* This function is not needed for spi mode, but need to be present.
* Without it defined the wlcore fallback to use the wrong packet
* allignment on tx.
*/
static void wl12xx_spi_set_block_size(struct device *child,
unsigned int blksz)
{
}
static struct wl1271_if_operations spi_ops = {
.read = wl12xx_spi_raw_read,
.write = wl12xx_spi_raw_write,
.reset = wl12xx_spi_reset,
.init = wl12xx_spi_init,
.power = wl12xx_spi_set_power,
.set_block_size = NULL,
.set_block_size = wl12xx_spi_set_block_size,
};
static const struct of_device_id wlcore_spi_of_match_table[] = {
{ .compatible = "ti,wl1271" },
{ .compatible = "ti,wl1271", .data = &wl12xx_data},
{ .compatible = "ti,wl1273", .data = &wl12xx_data},
{ .compatible = "ti,wl1281", .data = &wl12xx_data},
{ .compatible = "ti,wl1283", .data = &wl12xx_data},
{ .compatible = "ti,wl1801", .data = &wl18xx_data},
{ .compatible = "ti,wl1805", .data = &wl18xx_data},
{ .compatible = "ti,wl1807", .data = &wl18xx_data},
{ .compatible = "ti,wl1831", .data = &wl18xx_data},
{ .compatible = "ti,wl1835", .data = &wl18xx_data},
{ .compatible = "ti,wl1837", .data = &wl18xx_data},
{ }
};
MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table);
@ -375,18 +454,24 @@ static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue,
struct wlcore_platdev_data *pdev_data)
{
struct device_node *dt_node = spi->dev.of_node;
int ret;
const struct of_device_id *of_id;
of_id = of_match_node(wlcore_spi_of_match_table, dt_node);
if (!of_id)
return -ENODEV;
wilink_data = of_id->data;
dev_info(&spi->dev, "selected chip familiy is %s\n",
wilink_data->name);
if (of_find_property(dt_node, "clock-xtal", NULL))
pdev_data->ref_clock_xtal = true;
ret = of_property_read_u32(dt_node, "ref-clock-frequency",
&pdev_data->ref_clock_freq);
if (ret) {
dev_err(glue->dev,
"can't get reference clock frequency (%d)\n", ret);
return ret;
}
/* optional clock frequency params */
of_property_read_u32(dt_node, "ref-clock-frequency",
&pdev_data->ref_clock_freq);
of_property_read_u32(dt_node, "tcxo-clock-frequency",
&pdev_data->tcxo_clock_freq);
return 0;
}
@ -437,7 +522,8 @@ static int wl1271_probe(struct spi_device *spi)
return ret;
}
glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
glue->core = platform_device_alloc(wilink_data->name,
PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n");
return -ENOMEM;

View File

@ -171,6 +171,12 @@ struct wl_fw_status {
/* Tx rate of the last transmitted packet */
u8 tx_last_rate;
/* Tx rate or Tx rate estimate pre calculated by fw in mbps */
u8 tx_last_rate_mbps;
/* hlid for which the rates were reported */
u8 hlid;
} counters;
u32 log_start_addr;
@ -273,6 +279,12 @@ struct wl1271_link {
/* bitmap of TIDs where RX BA sessions are active for this link */
u8 ba_bitmap;
/* the last fw rate index we used for this link */
u8 fw_rate_idx;
/* the last fw rate [Mbps] we used for this link */
u8 fw_rate_mbps;
/* The wlvif this link belongs to. Might be null for global links */
struct wl12xx_vif *wlvif;
@ -335,6 +347,7 @@ struct wl1271_station {
* Used in both AP and STA mode.
*/
u64 total_freed_pkts;
struct wl1271 *wl;
};
struct wl12xx_vif {
@ -472,6 +485,7 @@ struct wl12xx_vif {
/* update rate conrol */
enum ieee80211_sta_rx_bandwidth rc_update_bw;
struct ieee80211_sta_ht_cap rc_ht_cap;
struct work_struct rc_update_work;
/*

View File

@ -40,6 +40,7 @@ struct ath9k_platform_data {
bool tx_gain_buffalo;
bool disable_2ghz;
bool disable_5ghz;
bool led_active_high;
int (*get_mac_revision)(void);
int (*external_reset)(void);

View File

@ -504,6 +504,9 @@
#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
#define BCMA_CCB_MII_MNG_CTL 0x0000
#define BCMA_CCB_MII_MNG_CMD_DATA 0x0004
/* BCM4331 ChipControl numbers. */
#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */
#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */