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. document describes the binding for the SPI connected chip.
Required properties: 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 - reg : Chip select address of device
- spi-max-frequency : Maximum SPI clocking speed of device in Hz - spi-max-frequency : Maximum SPI clocking speed of device in Hz
- ref-clock-frequency : Reference clock frequency
- interrupt-parent, interrupts : - interrupt-parent, interrupts :
Should contain parameters for 1 interrupt line. Should contain parameters for 1 interrupt line.
Interrupt parameters: parent, line number, type. 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: Optional properties:
- ref-clock-frequency : Reference clock frequency (should be set for wl12xx)
- clock-xtal : boolean, clock is generated from XTAL - clock-xtal : boolean, clock is generated from XTAL
- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt - Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
@ -21,16 +32,28 @@ Optional properties:
Examples: Examples:
For wl12xx family:
&spi1 { &spi1 {
wl1271@1 { wlcore: wlcore@1 {
compatible = "ti,wl1271"; compatible = "ti,wl1271";
reg = <1>; reg = <1>;
spi-max-frequency = <48000000>; spi-max-frequency = <48000000>;
clock-xtal;
ref-clock-frequency = <38400000>;
interrupt-parent = <&gpio3>; interrupt-parent = <&gpio3>;
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
vwlan-supply = <&vwlan_fixed>; 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 default y
config BCMA_SFLASH config BCMA_SFLASH
bool bool "ChipCommon-attached serial flash support"
depends on BCMA_DRIVER_MIPS depends on BCMA_HOST_SOC
default y 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 config BCMA_NFLASH
bool 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) void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
{ {
struct bcma_bus *bus = ccb->core->bus; struct bcma_bus *bus = ccb->core->bus;
void __iomem *mii = ccb->mii;
writel(offset, ccb->mii + 0x00); writel(offset, mii + BCMA_CCB_MII_MNG_CTL);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100); bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
writel(value, ccb->mii + 0x04); writel(value, mii + BCMA_CCB_MII_MNG_CMD_DATA);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100); bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
} }
EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write); 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, 0x4359) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) }, { 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_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, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },

View file

@ -114,7 +114,7 @@ config MTD_SST25L
config MTD_BCM47XXSFLASH config MTD_BCM47XXSFLASH
tristate "R/O support for serial flash on BCMA bus" tristate "R/O support for serial flash on BCMA bus"
depends on BCMA_SFLASH depends on BCMA_SFLASH && (MIPS || ARM)
help help
BCMA bus can have various flash memories attached, they are BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for 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, .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, .id = QCA9377_HW_1_0_DEV_VERSION,
.dev_id = QCA9377_1_0_DEVICE_ID, .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_10_4:
case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX: case ATH10K_FW_WMI_OP_VERSION_MAX:
WARN_ON(1); ath10k_err(ar, "htt op version not found from fw meta data");
return -EINVAL; return -EINVAL;
} }
} }
@ -2171,6 +2193,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->regs = &qca99x0_regs; ar->regs = &qca99x0_regs;
ar->hw_values = &qca99x0_values; ar->hw_values = &qca99x0_values;
break; break;
case ATH10K_HW_QCA9888:
ar->regs = &qca99x0_regs;
ar->hw_values = &qca9888_values;
break;
case ATH10K_HW_QCA4019: case ATH10K_HW_QCA4019:
ar->regs = &qca4019_regs; ar->regs = &qca4019_regs;
ar->hw_values = &qca4019_values; ar->hw_values = &qca4019_values;

View file

@ -165,6 +165,13 @@ struct ath10k_fw_stats_peer {
u32 rx_duration; 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 ath10k_fw_stats_vdev {
struct list_head list; struct list_head list;
@ -256,9 +263,11 @@ struct ath10k_fw_stats_pdev {
}; };
struct ath10k_fw_stats { struct ath10k_fw_stats {
bool extended;
struct list_head pdevs; struct list_head pdevs;
struct list_head vdevs; struct list_head vdevs;
struct list_head peers; struct list_head peers;
struct list_head peers_extd;
}; };
#define ATH10K_TPC_TABLE_TYPE_FLAG 1 #define ATH10K_TPC_TABLE_TYPE_FLAG 1
@ -667,6 +676,7 @@ struct ath10k_fw_components {
struct ath10k { struct ath10k {
struct ath_common ath_common; struct ath_common ath_common;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct ieee80211_ops *ops;
struct device *dev; struct device *dev;
u8 mac_addr[ETH_ALEN]; 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) static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
{ {
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false; 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_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); 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); 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.pdevs);
INIT_LIST_HEAD(&stats.vdevs); INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.peers); INIT_LIST_HEAD(&stats.peers);
INIT_LIST_HEAD(&stats.peers_extd);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); 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 * delivered which is treated as end-of-data and is itself discarded
*/ */
if (ath10k_peer_stats_enabled(ar)) 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 (ar->debug.fw_stats_done) {
if (!ath10k_peer_stats_enabled(ar)) 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.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); 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); complete(&ar->debug.fw_stats_complete);
@ -407,6 +422,7 @@ free:
ath10k_fw_stats_pdevs_free(&stats.pdevs); ath10k_fw_stats_pdevs_free(&stats.pdevs);
ath10k_fw_stats_vdevs_free(&stats.vdevs); ath10k_fw_stats_vdevs_free(&stats.vdevs);
ath10k_fw_stats_peers_free(&stats.peers); ath10k_fw_stats_peers_free(&stats.peers);
ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
spin_unlock_bh(&ar->data_lock); 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.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers); INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
return 0; return 0;
} }

View file

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

View file

@ -18,13 +18,15 @@
#include "wmi-ops.h" #include "wmi-ops.h"
#include "debug.h" #include "debug.h"
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head) static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
{ struct ieee80211_sta *sta; struct ath10k_fw_stats *stats)
struct ath10k_fw_stats_peer *peer; {
struct ath10k_fw_extd_stats_peer *peer;
struct ieee80211_sta *sta;
struct ath10k_sta *arsta; struct ath10k_sta *arsta;
rcu_read_lock(); 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, sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
NULL); NULL);
if (!sta) if (!sta)
@ -35,6 +37,48 @@ void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
rcu_read_unlock(); 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, static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
char __user *user_buf, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
@ -249,28 +293,6 @@ static const struct file_operations fops_delba = {
.llseek = default_llseek, .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, void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir) 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", S_IWUSR, dir, sta, &fops_addba);
debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); 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("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/list.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/semaphore.h>
#include <linux/timer.h> #include <linux/timer.h>
struct ath10k; 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)) if (WARN_ON_ONCE(!arvif))
return NULL; return NULL;
if (WARN_ON_ONCE(ath10k_mac_vif_chan(arvif->vif, &def))) if (ath10k_mac_vif_chan(arvif->vif, &def))
return NULL; return NULL;
return def.chan; 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); ath10k_htt_rx_delba(ar, resp);
break; break;
case HTT_T2H_MSG_TYPE_PKTLOG: { 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, trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
sizeof(*hdr) + skb->len -
__le16_to_cpu(hdr->size)); offsetof(struct htt_resp,
pktlog_msg.payload));
break; break;
} }
case HTT_T2H_MSG_TYPE_RX_FLUSH: { 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 ieee80211_txq *txq)
{ {
struct ath10k *ar = hw->priv; 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; struct ath10k_vif *arvif = (void *)txq->vif->drv_priv;
unsigned long frame_cnt; unsigned long frame_cnt;
unsigned long byte_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) if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL)
return; return;
if (txq->sta) if (txq->sta) {
arsta = (void *)txq->sta->drv_priv;
peer_id = arsta->peer_id; peer_id = arsta->peer_id;
else } else {
peer_id = arvif->peer_id; peer_id = arvif->peer_id;
}
tid = txq->tid; tid = txq->tid;
bit = BIT(peer_id % 32); bit = BIT(peer_id % 32);
@ -388,6 +390,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
{ {
int size; int size;
tasklet_kill(&htt->txrx_compl_task);
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
idr_destroy(&htt->pending_tx); 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 ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath10k_skb_cb *cb = ATH10K_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; return ar->scan.vdev_id;
else if (cb->vif) } else if (cb->vif) {
arvif = (void *)cb->vif->drv_priv;
return arvif->vdev_id; return arvif->vdev_id;
else if (ar->monitor_started) } else if (ar->monitor_started) {
return ar->monitor_vdev_id; return ar->monitor_vdev_id;
else } else {
return 0; return 0;
}
} }
static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth) static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth)

View file

@ -19,7 +19,6 @@
#include "hw.h" #include "hw.h"
const struct ath10k_hw_regs qca988x_regs = { const struct ath10k_hw_regs qca988x_regs = {
.rtc_state_cold_reset_mask = 0x00000400,
.rtc_soc_base_address = 0x00004000, .rtc_soc_base_address = 0x00004000,
.rtc_wmac_base_address = 0x00005000, .rtc_wmac_base_address = 0x00005000,
.soc_core_base_address = 0x00009000, .soc_core_base_address = 0x00009000,
@ -46,7 +45,6 @@ const struct ath10k_hw_regs qca988x_regs = {
}; };
const struct ath10k_hw_regs qca6174_regs = { const struct ath10k_hw_regs qca6174_regs = {
.rtc_state_cold_reset_mask = 0x00002000,
.rtc_soc_base_address = 0x00000800, .rtc_soc_base_address = 0x00000800,
.rtc_wmac_base_address = 0x00001000, .rtc_wmac_base_address = 0x00001000,
.soc_core_base_address = 0x0003a000, .soc_core_base_address = 0x0003a000,
@ -73,7 +71,6 @@ const struct ath10k_hw_regs qca6174_regs = {
}; };
const struct ath10k_hw_regs qca99x0_regs = { const struct ath10k_hw_regs qca99x0_regs = {
.rtc_state_cold_reset_mask = 0x00000400,
.rtc_soc_base_address = 0x00080000, .rtc_soc_base_address = 0x00080000,
.rtc_wmac_base_address = 0x00000000, .rtc_wmac_base_address = 0x00000000,
.soc_core_base_address = 0x00082000, .soc_core_base_address = 0x00082000,
@ -168,6 +165,15 @@ const struct ath10k_hw_values qca99x0_values = {
.ce_desc_meta_data_lsb = 4, .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 = { const struct ath10k_hw_values qca4019_values = {
.ce_count = 12, .ce_count = 12,
.num_target_ce_config_wlan = 10, .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: case ATH10K_HW_CC_WRAP_SHIFTED_EACH:
if (cc < cc_prev) if (cc < cc_prev)
cc_fix = 0x7fffffff; cc_fix = 0x7fffffff;
else
if (rcc < rcc_prev)
rcc_fix = 0x7fffffff; rcc_fix = 0x7fffffff;
break; break;
case ATH10K_HW_CC_WRAP_DISABLED: case ATH10K_HW_CC_WRAP_DISABLED:

View file

@ -26,6 +26,7 @@
#define QCA6164_2_1_DEVICE_ID (0x0041) #define QCA6164_2_1_DEVICE_ID (0x0041)
#define QCA6174_2_1_DEVICE_ID (0x003e) #define QCA6174_2_1_DEVICE_ID (0x003e)
#define QCA99X0_2_0_DEVICE_ID (0x0040) #define QCA99X0_2_0_DEVICE_ID (0x0040)
#define QCA9888_2_0_DEVICE_ID (0x0056)
#define QCA9984_1_0_DEVICE_ID (0x0046) #define QCA9984_1_0_DEVICE_ID (0x0046)
#define QCA9377_1_0_DEVICE_ID (0x0042) #define QCA9377_1_0_DEVICE_ID (0x0042)
#define QCA9887_1_0_DEVICE_ID (0x0050) #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_BOARD_DATA_FILE "board.bin"
#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234 #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 */ /* QCA9377 1.0 definitions */
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0" #define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
@ -210,6 +219,7 @@ enum ath10k_hw_rev {
ATH10K_HW_QCA988X, ATH10K_HW_QCA988X,
ATH10K_HW_QCA6174, ATH10K_HW_QCA6174,
ATH10K_HW_QCA99X0, ATH10K_HW_QCA99X0,
ATH10K_HW_QCA9888,
ATH10K_HW_QCA9984, ATH10K_HW_QCA9984,
ATH10K_HW_QCA9377, ATH10K_HW_QCA9377,
ATH10K_HW_QCA4019, ATH10K_HW_QCA4019,
@ -217,7 +227,6 @@ enum ath10k_hw_rev {
}; };
struct ath10k_hw_regs { struct ath10k_hw_regs {
u32 rtc_state_cold_reset_mask;
u32 rtc_soc_base_address; u32 rtc_soc_base_address;
u32 rtc_wmac_base_address; u32 rtc_wmac_base_address;
u32 soc_core_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 qca988x_values;
extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca6174_values;
extern const struct ath10k_hw_values qca99x0_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; extern const struct ath10k_hw_values qca4019_values;
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, 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_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) #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_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_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984)
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377) #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019) #define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
@ -296,25 +307,6 @@ enum ath10k_mcast2ucast_mode {
ATH10K_MCAST2UCAST_ENABLED = 1, 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 { enum ath10k_hw_rate_ofdm {
ATH10K_HW_RATE_OFDM_48M = 0, ATH10K_HW_RATE_OFDM_48M = 0,
ATH10K_HW_RATE_OFDM_24M, ATH10K_HW_RATE_OFDM_24M,
@ -535,7 +527,6 @@ enum ath10k_hw_cc_wraparound_type {
/* as of IP3.7.1 */ /* as of IP3.7.1 */
#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on #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_LSB 0
#define RTC_STATE_V_MASK 0x00000007 #define RTC_STATE_V_MASK 0x00000007
#define RTC_STATE_ADDRESS 0x0000 #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; struct ath10k_peer *peer, *tmp;
int peer_id; int peer_id;
int i;
lockdep_assert_held(&ar->conf_mutex); 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; 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); list_del(&peer->list);
kfree(peer); kfree(peer);
ar->num_peers--; 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) static void ath10k_peer_cleanup_all(struct ath10k *ar)
{ {
struct ath10k_peer *peer, *tmp; struct ath10k_peer *peer, *tmp;
int i;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
@ -836,6 +849,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
list_del(&peer->list); list_del(&peer->list);
kfree(peer); kfree(peer);
} }
for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++)
ar->peer_map[i] = NULL;
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
ar->num_peers = 0; ar->num_peers = 0;
@ -2939,7 +2956,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
if (channel->flags & IEEE80211_CHAN_DISABLED) if (channel->flags & IEEE80211_CHAN_DISABLED)
continue; continue;
ch->allow_ht = true; ch->allow_ht = true;
/* FIXME: when should we really allow VHT? */ /* FIXME: when should we really allow VHT? */
ch->allow_vht = true; 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) static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
{ {
struct ath10k_txq *artxq = (void *)txq->drv_priv; struct ath10k_txq *artxq;
if (!txq) if (!txq)
return; return;
artxq = (void *)txq->drv_priv;
INIT_LIST_HEAD(&artxq->list); INIT_LIST_HEAD(&artxq->list);
} }
static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) 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 ath10k_skb_cb *cb;
struct sk_buff *msdu; struct sk_buff *msdu;
int msdu_id; int msdu_id;
@ -3693,6 +3711,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
if (!txq) if (!txq)
return; return;
artxq = (void *)txq->drv_priv;
spin_lock_bh(&ar->txqs_lock); spin_lock_bh(&ar->txqs_lock);
if (!list_empty(&artxq->list)) if (!list_empty(&artxq->list))
list_del_init(&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); 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.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap.vht_mcs.tx_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; 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; ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
if (ar->ht_cap_info & WMI_HT_CAP_RX_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; continue;
if (peer->sta == sta) { if (peer->sta == sta) {
ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n", ath10k_warn(ar, "found sta peer %pM (ptr %p id %d) entry on vdev %i after it was supposedly removed\n",
sta->addr, arvif->vdev_id); sta->addr, peer, i, arvif->vdev_id);
peer->sta = NULL; 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); spin_unlock_bh(&ar->data_lock);
@ -7406,6 +7436,7 @@ static const struct ieee80211_ops ath10k_ops = {
#endif #endif
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs, .sta_add_debugfs = ath10k_sta_add_debugfs,
.sta_statistics = ath10k_sta_statistics,
#endif #endif
}; };
@ -7475,21 +7506,32 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
struct ath10k *ath10k_mac_create(size_t priv_size) struct ath10k *ath10k_mac_create(size_t priv_size)
{ {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct ieee80211_ops *ops;
struct ath10k *ar; struct ath10k *ar;
hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops); ops = kmemdup(&ath10k_ops, sizeof(ath10k_ops), GFP_KERNEL);
if (!hw) if (!ops)
return NULL; return NULL;
hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops);
if (!hw) {
kfree(ops);
return NULL;
}
ar = hw->priv; ar = hw->priv;
ar->hw = hw; ar->hw = hw;
ar->ops = ops;
return ar; return ar;
} }
void ath10k_mac_destroy(struct ath10k *ar) void ath10k_mac_destroy(struct ath10k *ar)
{ {
struct ieee80211_ops *ops = ar->ops;
ieee80211_free_hw(ar->hw); ieee80211_free_hw(ar->hw);
kfree(ops);
} }
static const struct ieee80211_iface_limit ath10k_if_limits[] = { 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"); 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, ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier); ath10k_reg_notifier);
if (ret) { 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, 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, 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, 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, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */
{ PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */ { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */
{ PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */ { 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 }, { 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_0_CHIP_ID_REV },
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_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) & CORE_CTRL_ADDRESS) &
0x7ff) << 21; 0x7ff) << 21;
break; break;
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984: case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA4019: case ATH10K_HW_QCA4019:
@ -1583,6 +1587,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
break; break;
case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984: case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA4019: case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0 /* TODO: Find appropriate register configuration for QCA99X0
* to mask irq/MSI. * to mask irq/MSI.
@ -1608,6 +1613,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
break; break;
case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA9984: case ATH10K_HW_QCA9984:
case ATH10K_HW_QCA9888:
case ATH10K_HW_QCA4019: case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0 /* TODO: Find appropriate register configuration for QCA99X0
* to unmask irq/MSI. * to unmask irq/MSI.
@ -1948,6 +1954,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
switch (ar_pci->pdev->device) { switch (ar_pci->pdev->device) {
case QCA988X_2_0_DEVICE_ID: case QCA988X_2_0_DEVICE_ID:
case QCA99X0_2_0_DEVICE_ID: case QCA99X0_2_0_DEVICE_ID:
case QCA9888_2_0_DEVICE_ID:
case QCA9984_1_0_DEVICE_ID: case QCA9984_1_0_DEVICE_ID:
case QCA9887_1_0_DEVICE_ID: case QCA9887_1_0_DEVICE_ID:
return 1; return 1;
@ -2216,6 +2223,14 @@ static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); 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 */ /* this function effectively clears target memory controller assert line */
static void ath10k_pci_warm_reset_si0(struct ath10k *ar) 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); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret; int ret;
if (ath10k_pci_has_device_gone(ar))
return IRQ_NONE;
ret = ath10k_pci_force_wake(ar); ret = ath10k_pci_force_wake(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to wake device up on irq: %d\n", 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_soft_reset = ath10k_pci_qca99x0_soft_chip_reset;
pci_hard_reset = ath10k_pci_qca99x0_chip_reset; pci_hard_reset = ath10k_pci_qca99x0_chip_reset;
break; 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: case QCA9377_1_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA9377; hw_rev = ATH10K_HW_QCA9377;
pci_ps = true; pci_ps = true;

View file

@ -101,9 +101,9 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
break; break;
case 80: case 80:
/* TODO: As experiments with an analogue sender and various /* 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 * 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. * for that is found, don't report these samples.
*/ */
if (bin_len == 64) 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); skb_cb = ATH10K_SKB_CB(msdu);
txq = skb_cb->txq; txq = skb_cb->txq;
artxq = (void *)txq->drv_priv;
if (txq) if (txq) {
artxq = (void *)txq->drv_priv;
artxq->num_fw_queued--; artxq->num_fw_queued--;
}
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
ath10k_htt_tx_dec_pending(htt); 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", ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
ev->vdev_id, ev->addr, ev->peer_id); 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; ar->peer_map[ev->peer_id] = peer;
set_bit(ev->peer_id, peer->peer_ids); set_bit(ev->peer_id, peer->peer_ids);
exit: exit:

View file

@ -1826,7 +1826,7 @@ static struct sk_buff *
ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{ {
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(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 wmi_mgmt_tx_cmd *cmd;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct sk_buff *skb; 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; hdr = (struct ieee80211_hdr *)msdu->data;
fc = le16_to_cpu(hdr->frame_control); fc = le16_to_cpu(hdr->frame_control);
if (cb->vif) if (cb->vif) {
arvif = (void *)cb->vif->drv_priv;
vdev_id = arvif->vdev_id; vdev_id = arvif->vdev_id;
else } else {
vdev_id = 0; vdev_id = 0;
}
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
return ERR_PTR(-EINVAL); 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_pdev_ext_stats;
u32 num_vdev_stats; u32 num_vdev_stats;
u32 num_peer_stats; u32 num_peer_stats;
u32 num_bcnflt_stats;
u32 stats_id; u32 stats_id;
int i; 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_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
num_peer_stats = __le32_to_cpu(ev->num_peer_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); stats_id = __le32_to_cpu(ev->stats_id);
for (i = 0; i < num_pdev_stats; i++) { 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 */ /* fw doesn't implement vdev stats */
for (i = 0; i < num_peer_stats; i++) { 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; 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; src = (void *)skb->data;
if (!skb_pull(skb, stats_len)) if (!skb_pull(skb, sizeof(*src)))
return -EPROTO; return -EPROTO;
dst = kzalloc(sizeof(*dst), GFP_ATOMIC); dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst) if (!dst)
continue; continue;
ath10k_wmi_10_4_pull_peer_stats(&src->common, dst); ath10k_wmi_10_4_pull_peer_stats(src, dst);
/* FIXME: expose 10.4 specific values */
if (extd_peer_stats)
dst->rx_duration = __le32_to_cpu(src->rx_duration);
list_add_tail(&dst->list, &stats->peers); 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; 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: case WMI_10_4_PEER_STA_KICKOUT_EVENTID:
ath10k_wmi_event_peer_sta_kickout(ar, skb); ath10k_wmi_event_peer_sta_kickout(ar, skb);
break; break;
case WMI_10_4_ROAM_EVENTID:
ath10k_wmi_event_roam(ar, skb);
break;
case WMI_10_4_HOST_SWBA_EVENTID: case WMI_10_4_HOST_SWBA_EVENTID:
ath10k_wmi_event_host_swba(ar, skb); ath10k_wmi_event_host_swba(ar, skb);
break; 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_phyerr = ath10k_wmi_10_4_op_pull_phyerr_ev,
.pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
.pull_rdy = ath10k_wmi_op_pull_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, .get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme,
.gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,

View file

@ -4340,7 +4340,6 @@ struct wmi_10_4_peer_stats {
} __packed; } __packed;
struct wmi_10_4_peer_extd_stats { struct wmi_10_4_peer_extd_stats {
struct wmi_10_4_peer_stats common;
struct wmi_mac_addr peer_macaddr; struct wmi_mac_addr peer_macaddr;
__le32 inactive_time; __le32 inactive_time;
__le32 peer_chain_rssi; __le32 peer_chain_rssi;
@ -4348,6 +4347,19 @@ struct wmi_10_4_peer_extd_stats {
__le32 reserved[10]; __le32 reserved[10];
} __packed; } __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 { struct wmi_10_2_pdev_ext_stats {
__le32 rx_rssi_comb; __le32 rx_rssi_comb;
__le32 rx_rssi[4]; __le32 rx_rssi[4];

View file

@ -847,8 +847,6 @@ static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
up(&ar->sem); up(&ar->sem);
vif->sme_state = SME_DISCONNECTED;
return 0; return 0;
} }
@ -1111,7 +1109,8 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
cfg80211_chandef_create(&chandef, cfg80211_chandef_create(&chandef,
ieee80211_get_channel(vif->ar->wiphy, freq), 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); NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
mutex_lock(&vif->wdev.mtx); 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); ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECTED, &vif->flags);
netif_carrier_off(vif->ndev);
/* Restore ht setting in firmware */ /* Restore ht setting in firmware */
return ath6kl_restore_htcap(vif); return ath6kl_restore_htcap(vif);

View file

@ -1401,6 +1401,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return; 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 */ /* Get the Power save state of the STA */
if (vif->nw_type == AP_NETWORK) { if (vif->nw_type == AP_NETWORK) {
meta_type = wmi_data_hdr_get_meta(dhdr); 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) & ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) &
WMI_DATA_HDR_PS_MASK); 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); trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG);
switch (meta_type) { 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); seq_no = wmi_data_hdr_get_seqno(dhdr);
meta_type = wmi_data_hdr_get_meta(dhdr); meta_type = wmi_data_hdr_get_meta(dhdr);
dot11_hdr = wmi_data_hdr_get_dot11(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)); skb_pull(skb, sizeof(struct wmi_data_hdr));

View file

@ -18,7 +18,6 @@
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h> #include <linux/module.h>
#include "ath9k.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) static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{ {
struct ath_softc *sc = (struct ath_softc *)common->priv; ath_err(common, "%s: eeprom data has to be provided externally\n",
struct platform_device *pdev = to_platform_device(sc->dev); __func__);
struct ath9k_platform_data *pdata; return false;
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;
} }
static struct ath_bus_ops ath_ahb_bus_ops = { 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, static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
struct ath_spec_scan *param) struct ath_spec_scan *param)
{ {
u32 repeat_bit;
u8 count; u8 count;
if (!param->enabled) { 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_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
if (param->short_repeat) if (AR_SREV_9280(ah))
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
else else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI;
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
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 /* on AR92xx, the highest bit of count will make the the chip send
* spectral samples endlessly. Check if this really was intended, * 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; count = param->count;
if (param->endless) { if (param->endless) {
if (AR_SREV_9271(ah)) if (AR_SREV_9280(ah))
count = 0;
else
count = 0x80; count = 0x80;
else
count = 0;
} else if (count & 0x80) } else if (count & 0x80)
count = 0x7f; 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, REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, 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_PERIOD_S 8
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ #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_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 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_RX_DELAY 0x9914
#define AR_PHY_SEARCH_START_DELAY 0x9918 #define AR_PHY_SEARCH_START_DELAY 0x9918

View file

@ -33,6 +33,7 @@ struct coeff {
enum ar9003_cal_types { enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0), IQ_MISMATCH_CAL = BIT(0),
TEMP_COMP_CAL = BIT(1),
}; };
static void ar9003_hw_setup_calibration(struct ath_hw *ah, 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 */ /* Kick-off cal */
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
break; 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: default:
ath_err(common, "Invalid calibration type\n"); ath_err(common, "Invalid calibration type\n");
break; break;
@ -75,50 +82,51 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal) struct ath9k_cal_list *currCal)
{ {
struct ath9k_hw_cal_data *caldata = ah->caldata; struct ath9k_hw_cal_data *caldata = ah->caldata;
/* Cal is assumed not done until explicitly set below */ const struct ath9k_percal_data *cur_caldata = currCal->calData;
bool iscaldone = false;
/* Calibration in progress. */ /* Calibration in progress. */
if (currCal->calState == CAL_RUNNING) { if (currCal->calState == CAL_RUNNING) {
/* Check to see if it has finished. */ /* 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); if (cur_caldata->calPostProc)
ah->cal_samples++; cur_caldata->calPostProc(ah, numChains);
if (ah->cal_samples >= /* Calibration has finished. */
currCal->calData->calNumSamples) { caldata->CalValid |= cur_caldata->calType;
unsigned int i, numChains = 0; currCal->calState = CAL_DONE;
for (i = 0; i < AR9300_MAX_CHAINS; i++) { return true;
if (rxchainmask & (1 << i)) } else {
numChains++;
}
/*
* Process accumulated data
*/
currCal->calData->calPostProc(ah, numChains);
/* Calibration has finished. */
caldata->CalValid |= currCal->calData->calType;
currCal->calState = CAL_DONE;
iscaldone = true;
} else {
/* /*
* Set-up collection of another sub-sample until we * Set-up collection of another sub-sample until we
* get desired number * get desired number
*/ */
ar9003_hw_setup_calibration(ah, currCal); 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 */ /* If current cal is marked invalid in channel, kick it off */
ath9k_hw_reset_calibration(ah, currCal); ath9k_hw_reset_calibration(ah, currCal);
} }
return iscaldone; return false;
} }
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, 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 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) static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
{ {
ah->iq_caldata.calData = &iq_cal_single_sample; ah->iq_caldata.calData = &iq_cal_single_sample;
ah->temp_caldata.calData = &temp_cal_single_sample;
if (AR_SREV_9300_20_OR_LATER(ah)) { if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->enabled_cals |= TX_IQ_CAL; 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->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 #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, static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
struct ath9k_channel *chan) struct ath9k_channel *chan)
{ {
@ -1533,21 +1571,7 @@ skip_tx_iqcal:
/* Revert chainmask to runtime parameters */ /* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
/* Initialize list pointers */ ar9003_hw_init_cal_common(ah);
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;
return true; 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, static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan) 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 txiqcal_done = false;
bool status = true; bool status = true;
bool run_agc_cal = false, sep_iq_cal = false; bool run_agc_cal = false, sep_iq_cal = false;
@ -1677,21 +1699,7 @@ skip_tx_iqcal:
/* Revert chainmask to runtime parameters */ /* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
/* Initialize list pointers */ ar9003_hw_init_cal_common(ah);
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;
return true; 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)) if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
ar9003_hw_internal_regulator_apply(ah); ar9003_hw_internal_regulator_apply(ah);
ar9003_hw_apply_tuning_caps(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_txend_to_xpa_off_apply(ah, is2ghz);
ar9003_hw_thermometer_apply(ah); ar9003_hw_thermometer_apply(ah);
ar9003_hw_thermo_cal_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 (AR_SREV_9550(ah) ? 0x3c0 : 0x300)
#define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) #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 (0xffff)
#define AR_SWITCH_TABLE_COM_ALL_S (0) #define AR_SWITCH_TABLE_COM_ALL_S (0)
#define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff)
@ -712,15 +705,17 @@
#define AR_SWITCH_TABLE_ALL (0xfff) #define AR_SWITCH_TABLE_ALL (0xfff)
#define AR_SWITCH_TABLE_ALL_S (0) #define AR_SWITCH_TABLE_ALL_S (0)
#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ #define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) ((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_CH0_THERM_LOCAL 0x80000000
#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 #define AR_CH0_THERM_START 0x20000000
#define AR_PHY_65NM_CH0_THERM_START 0x20000000 #define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00
#define AR_PHY_65NM_CH0_THERM_START_S 29 #define AR_CH0_THERM_SAR_ADC_OUT_S 8
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00
#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
(AR_SREV_9462(ah) ? 0x16290 : 0x16284)) (AR_SREV_9462(ah) ? 0x16290 : 0x16284))

View file

@ -637,6 +637,8 @@ struct ath9k_vif_iter_data {
int nwds; /* number of WDS vifs */ int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */ int nadhocs; /* number of adhoc vifs */
int nocbs; /* number of OCB vifs */ int nocbs; /* number of OCB vifs */
int nbcnvifs; /* number of beaconing vifs */
struct ieee80211_vif *primary_beacon_vif;
struct ieee80211_vif *primary_sta; struct ieee80211_vif *primary_sta;
}; };
@ -685,10 +687,11 @@ struct ath_beacon {
}; };
void ath9k_beacon_tasklet(unsigned long data); void ath9k_beacon_tasklet(unsigned long data);
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
u32 changed); bool beacons);
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); 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_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); void ath9k_set_beacon(struct ath_softc *sc);
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_csa_update(struct ath_softc *sc); 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]; txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs; 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; qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 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->beacon.bslot[avp->av_bslot] = vif;
sc->nbcnvifs++;
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
avp->av_bslot); 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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv; struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_buf *bf = avp->av_bcbuf; 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", ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
avp->av_bslot); avp->av_bslot);
tasklet_disable(&sc->bcon_tasklet); tasklet_disable(&sc->bcon_tasklet);
cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
if (bf && bf->bf_mpdu) { if (bf && bf->bf_mpdu) {
struct sk_buff *skb = bf->bf_mpdu; struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr, 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; avp->av_bcbuf = NULL;
sc->beacon.bslot[avp->av_bslot] = NULL; sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
list_add_tail(&bf->list, &sc->beacon.bbuf); list_add_tail(&bf->list, &sc->beacon.bbuf);
tasklet_enable(&sc->bcon_tasklet); 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) static int ath9k_beacon_choose_slot(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); 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; 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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv; s64 tsfadjust;
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon; int slot;
u32 tsfadjust;
if (avp->av_bslot == 0) for (slot = 0; slot < ATH_BCBUF; slot++) {
return; struct ath_vif *avp;
tsfadjust = cur_conf->beacon_interval * avp->av_bslot; if (!sc->beacon.bslot[slot])
tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF; continue;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", avp = (void *)sc->beacon.bslot[slot]->drv_priv;
(unsigned long long)tsfadjust, avp->av_bslot);
/* 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) 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. * Both nexttbtt and intval have to be in usecs.
*/ */
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, 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; struct ath_hw *ah = sc->sc_ah;
ath9k_hw_disable_interrupts(ah); ath9k_hw_disable_interrupts(ah);
if (reset_tsf)
ath9k_hw_reset_tsf(ah);
ath9k_beaconq_config(sc); ath9k_beaconq_config(sc);
ath9k_hw_beaconinit(ah, nexttbtt, intval); ath9k_hw_beaconinit(ah, nexttbtt, intval);
ah->imask |= ATH9K_INT_SWBA;
sc->beacon.bmisscnt = 0; sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah); ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_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 * 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 * 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; struct ath_hw *ah = sc->sc_ah;
ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); 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, 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_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 * 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); 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, static void ath9k_cache_beacon_config(struct ath_softc *sc,
struct ath_chanctx *ctx, struct ath_chanctx *ctx,
struct ieee80211_bss_conf *bss_conf) 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) if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1; cur_conf->dtim_period = 1;
ath9k_set_tsfadjust(sc, cur_conf);
} }
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
u32 changed) bool beacons)
{ {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_hw *ah = sc->sc_ah;
struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah);
struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp;
struct ath_vif *avp = (void *)vif->drv_priv; struct ath_chanctx *ctx;
struct ath_chanctx *ctx = avp->chanctx;
struct ath_beacon_config *cur_conf; struct ath_beacon_config *cur_conf;
unsigned long flags; unsigned long flags;
bool enabled;
bool skip_beacon = false; 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; return;
cur_conf = &avp->chanctx->beacon; avp = (void *)main_vif->drv_priv;
if (vif->type == NL80211_IFTYPE_AP) ctx = avp->chanctx;
ath9k_set_tsfadjust(sc, vif); cur_conf = &ctx->beacon;
enabled = cur_conf->enable_beacon;
cur_conf->enable_beacon = beacons;
if (!ath9k_allow_beacon_config(sc, vif)) if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
return; ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
if (vif->type == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, ctx, bss_conf);
if (ctx != sc->cur_chan)
return;
ath9k_set_beacon(sc); ath9k_set_beacon(sc);
set_bit(ATH_OP_BEACONS, &common->op_flags); set_bit(ATH_OP_BEACONS, &common->op_flags);
return; return;
} }
/* /* Update the beacon configuration. */
* Take care of multiple interfaces when ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
* 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;
/* /*
* Configure the HW beacon registers only when we have a valid * Configure the HW beacon registers only when we have a valid
* beacon interval. * beacon interval.
*/ */
if (cur_conf->beacon_interval) { if (cur_conf->beacon_interval) {
/* /* Special case to sync the TSF when joining an existing IBSS.
* If we are joining an existing IBSS network, start beaconing * This is only done if no AP interface is active.
* only after a TSF-sync has taken place. Ensure that this * Note that mac80211 always resets the TSF when creating a new
* happens by setting the appropriate flags. * IBSS interface.
*/ */
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
bss_conf->enable_beacon) { !enabled && beacons && !main_vif->bss_conf.ibss_creator) {
spin_lock_irqsave(&sc->sc_pm_lock, flags); spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags); spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
skip_beacon = true; skip_beacon = true;
} else {
ath9k_set_beacon(sc);
} }
/* /*
* Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
* here, it is done in ath9k_beacon_config_adhoc(). * 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); set_bit(ATH_OP_BEACONS, &common->op_flags);
else ath9k_set_beacon(sc);
} else {
clear_bit(ATH_OP_BEACONS, &common->op_flags); 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) #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
struct ath_beacon_config { struct ath_beacon_config {
struct ieee80211_vif *main_vif;
int beacon_interval; int beacon_interval;
u16 dtim_period; u16 dtim_period;
u16 bmiss_timeout; 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) void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
{ {
/* ackto = slottime + sifs + air delay */ /* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = &ah->dynack; struct ath_dynack *da = &ah->dynack;
an->ackto = ackto; an->ackto = ackto;
@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
void ath_dynack_reset(struct ath_hw *ah) void ath_dynack_reset(struct ath_hw *ah)
{ {
/* ackto = slottime + sifs + air delay */ /* ackto = slottime + sifs + air delay */
u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = &ah->dynack; struct ath_dynack *da = &ah->dynack;
da->lto = jiffies; da->lto = jiffies;

View file

@ -15,6 +15,7 @@
*/ */
#include "hw.h" #include "hw.h"
#include <linux/ath9k_platform.h>
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) 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, static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
u16 *data) off_t offset, u16 *data)
{ {
u16 *blob_data; if (offset > blob_size)
if (off * sizeof(u16) > ah->eeprom_blob->size)
return false; return false;
blob_data = (u16 *)ah->eeprom_blob->data; *data = blob[offset];
*data = blob_data[off];
return true; 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) bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_platform_data *pdata = ah->dev->platform_data;
bool ret; bool ret;
if (ah->eeprom_blob) 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 else
ret = common->bus_ops->eeprom_read(common, off, data); 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 * Long slot time : 2x cwmin
* Short slot time : 4x 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; qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin; 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++) for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->beacon.bslot[i] = NULL; 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_channels_rates(common);
ath9k_cmn_init_crypto(ah); 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)) if (AR_SREV_9100(ah))
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
ah->slottime = ATH9K_SLOT_TIME_9; ah->slottime = 9;
ah->globaltxtimeout = (u32) -1; ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED; ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true; 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); 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); struct ath_common *common = ath9k_hw_common(ah);
u32 sum;
int i; int i;
u16 eeval; u16 eeval;
static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; 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++) { for (i = 0; i < 3; i++) {
eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]); eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]);
sum += eeval;
common->macaddr[2 * i] = eeval >> 8; common->macaddr[2 * i] = eeval >> 8;
common->macaddr[2 * i + 1] = eeval & 0xff; 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); if (is_valid_ether_addr(common->macaddr))
ath_err(common, return;
"random mac address will be used: %pM\n",
common->macaddr);
}
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) 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) if (r)
return r; return r;
r = ath9k_hw_init_macaddr(ah); ath9k_hw_init_macaddr(ah);
if (r) {
ath_err(common, "Failed to initialize MAC address\n");
return r;
}
ath9k_hw_init_hang_checks(ah); ath9k_hw_init_hang_checks(ah);
common->state = ATH_HW_INITIALIZED; common->state = ATH_HW_INITIALIZED;
@ -1832,8 +1828,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 saveLedState; u32 saveLedState;
u32 saveDefAntenna; u32 saveDefAntenna;
u32 macStaId1; u32 macStaId1;
struct timespec tsf_ts;
u32 tsf_offset;
u64 tsf = 0; u64 tsf = 0;
s64 usec = 0;
int r; int r;
bool start_mci_reset = false; bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep; 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; macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
/* Save TSF before chip reset, a cold reset clears it */ /* Save TSF before chip reset, a cold reset clears it */
getrawmonotonic(&tsf_ts);
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(ah);
usec = ktime_to_us(ktime_get_raw());
saveLedState = REG_READ(ah, AR_CFG_LED) & saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | (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 */ /* Restore TSF */
usec = ktime_to_us(ktime_get_raw()) - usec; tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
ath9k_hw_settsf64(ah, tsf + usec); ath9k_hw_settsf64(ah, tsf + tsf_offset);
if (AR_SREV_9280_20_OR_LATER(ah)) if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); 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 * Some AR91xx SoC devices frequently fail to accept TSF writes
* right after the chip reset. When that happens, write a new * right after the chip reset. When that happens, write a new
* value after the initvals have been applied, with an offset * value after the initvals have been applied.
* based on measured time difference
*/ */
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) { if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
tsf += 1500; tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
ath9k_hw_settsf64(ah, tsf); ath9k_hw_settsf64(ah, tsf + tsf_offset);
} }
ath9k_hw_init_mfp(ah); ath9k_hw_init_mfp(ah);

View file

@ -830,6 +830,7 @@ struct ath_hw {
/* Calibration */ /* Calibration */
u32 supp_cals; u32 supp_cals;
struct ath9k_cal_list iq_caldata; struct ath9k_cal_list iq_caldata;
struct ath9k_cal_list temp_caldata;
struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcgain_caldata;
struct ath9k_cal_list adcdc_caldata; struct ath9k_cal_list adcdc_caldata;
struct ath9k_cal_list *cal_list; 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; common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); 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++) for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
sc->beacon.bslot[i] = NULL; 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); 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 ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
int ret = 0; struct ath_common *common = ath9k_hw_common(ah);
int ret;
if (!pdata) if (!pdata)
return 0; 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) { if (pdata->eeprom_name) {
ret = ath9k_eeprom_request(sc, pdata->eeprom_name); ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
if (ret) if (ret)
return ret; return ret;
} }
if (pdata->led_active_high)
ah->config.led_active_high = true;
if (pdata->tx_gain_buffalo) if (pdata->tx_gain_buffalo)
ah->config.tx_gain_buffalo = true; 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, static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops) const struct ath_bus_ops *bus_ops)
{ {
struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = NULL; struct ath_hw *ah = NULL;
struct ath9k_hw_capabilities *pCap; struct ath9k_hw_capabilities *pCap;
struct ath_common *common; struct ath_common *common;
@ -550,6 +571,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ah->dev = sc->dev; ah->dev = sc->dev;
ah->hw = sc->hw; ah->hw = sc->hw;
ah->hw_version.devid = devid; ah->hw_version.devid = devid;
ah->ah_flags |= AH_USE_EEPROM;
ah->led_pin = -1;
ah->reg_ops.read = ath9k_ioread32; ah->reg_ops.read = ath9k_ioread32;
ah->reg_ops.multi_read = ath9k_multi_ioread32; ah->reg_ops.multi_read = ath9k_multi_ioread32;
ah->reg_ops.write = ath9k_iowrite32; 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()) if (!ath9k_is_chanctx_enabled())
sc->cur_chan->hw_queue_base = 0; 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->ops = &ah->reg_ops;
common->bus_ops = bus_ops; common->bus_ops = bus_ops;
common->ps_ops = &ath9k_ps_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); ath9k_init_pcoem_platform(sc);
ret = ath9k_init_soc_platform(sc); ret = ath9k_init_platform(sc);
if (ret) if (ret)
return ret; return ret;
@ -646,9 +653,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret) if (ret)
goto err_hw; goto err_hw;
if (pdata && pdata->macaddr)
memcpy(common->macaddr, pdata->macaddr, ETH_ALEN);
ret = ath9k_init_queues(sc); ret = ath9k_init_queues(sc);
if (ret) if (ret)
goto err_queues; goto err_queues;

View file

@ -65,10 +65,6 @@
#define INIT_SSH_RETRY 32 #define INIT_SSH_RETRY 32
#define INIT_SLG_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_XRETRY 0x01
#define ATH9K_TXERR_FILT 0x02 #define ATH9K_TXERR_FILT 0x02
#define ATH9K_TXERR_FIFO 0x04 #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, static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
u8 *mac, struct ieee80211_vif *vif) 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) if (!vif->bss_conf.use_short_slot)
iter_data->slottime = ATH9K_SLOT_TIME_20; iter_data->slottime = 20;
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
iter_data->naps++; iter_data->naps++;
if (vif->bss_conf.enable_beacon)
ath9k_vif_iter_set_beacon(iter_data, vif);
break; break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
iter_data->nstations++; iter_data->nstations++;
@ -943,12 +961,12 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
iter_data->nadhocs++; iter_data->nadhocs++;
if (vif->bss_conf.enable_beacon) if (vif->bss_conf.enable_beacon)
iter_data->beacons = true; ath9k_vif_iter_set_beacon(iter_data, vif);
break; break;
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
iter_data->nmeshes++; iter_data->nmeshes++;
if (vif->bss_conf.enable_beacon) if (vif->bss_conf.enable_beacon)
iter_data->beacons = true; ath9k_vif_iter_set_beacon(iter_data, vif);
break; break;
case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_WDS:
iter_data->nwds++; iter_data->nwds++;
@ -999,7 +1017,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
*/ */
memset(iter_data, 0, sizeof(*iter_data)); memset(iter_data, 0, sizeof(*iter_data));
eth_broadcast_addr(iter_data->mask); 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) list_for_each_entry(avp, &ctx->vifs, list)
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); 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->opmode = vif->type;
ah->imask &= ~ATH9K_INT_SWBA; ah->imask &= ~ATH9K_INT_SWBA;
ah->imask &= ~ATH9K_INT_TSFOOR; ah->imask &= ~ATH9K_INT_TSFOOR;
ah->slottime = ATH9K_SLOT_TIME_9; ah->slottime = 9;
ath_hw_setbssidmask(common); ath_hw_setbssidmask(common);
ath9k_hw_setopmode(ah); 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_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_vif_iter_data iter_data; struct ath9k_vif_iter_data iter_data;
struct ath_beacon_config *cur_conf;
ath_chanctx_check_active(sc, ctx); ath_chanctx_check_active(sc, ctx);
@ -1103,13 +1120,12 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ath_hw_setbssidmask(common); ath_hw_setbssidmask(common);
if (iter_data.naps > 0) { if (iter_data.naps > 0) {
cur_conf = &ctx->beacon;
ath9k_hw_set_tsfadjust(ah, true); ath9k_hw_set_tsfadjust(ah, true);
ah->opmode = NL80211_IFTYPE_AP; ah->opmode = NL80211_IFTYPE_AP;
if (cur_conf->enable_beacon)
iter_data.beacons = true;
} else { } else {
ath9k_hw_set_tsfadjust(ah, false); ath9k_hw_set_tsfadjust(ah, false);
if (iter_data.beacons)
ath9k_beacon_ensure_primary_slot(sc);
if (iter_data.nmeshes) if (iter_data.nmeshes)
ah->opmode = NL80211_IFTYPE_MESH_POINT; ah->opmode = NL80211_IFTYPE_MESH_POINT;
@ -1134,7 +1150,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
ctx->switch_after_beacon = true; ctx->switch_after_beacon = true;
} }
ah->imask &= ~ATH9K_INT_SWBA;
if (ah->opmode == NL80211_IFTYPE_STATION) { if (ah->opmode == NL80211_IFTYPE_STATION) {
bool changed = (iter_data.primary_sta != ctx->primary_sta); 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)) if (ath9k_hw_mci_is_enabled(sc->sc_ah))
ath9k_mci_update_wlan_channels(sc, true); 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); 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) { if (ah->slottime != iter_data.slottime) {
ah->slottime = iter_data.slottime; ah->slottime = iter_data.slottime;
ath9k_hw_init_global_settings(ah); 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) || if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
(changed & BSS_CHANGED_BEACON_INT) || (changed & BSS_CHANGED_BEACON_INT) ||
(changed & BSS_CHANGED_BEACON_INFO)) { (changed & BSS_CHANGED_BEACON_INFO)) {
ath9k_beacon_config(sc, vif, changed); ath9k_calculate_summary_state(sc, avp->chanctx);
if (changed & BSS_CHANGED_BEACON_ENABLED)
ath9k_calculate_summary_state(sc, avp->chanctx);
} }
if ((avp->chanctx == sc->cur_chan) && if ((avp->chanctx == sc->cur_chan) &&
@ -1788,6 +1797,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
slottime = 9; slottime = 9;
else else
slottime = 20; slottime = 20;
if (vif->type == NL80211_IFTYPE_AP) { if (vif->type == NL80211_IFTYPE_AP) {
/* /*
* Defer update, so that connected stations can adjust * 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) static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
u64 tsf; u64 tsf;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc); 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); ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
@ -1839,10 +1857,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
u64 tsf) u64 tsf)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc); 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); ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex); 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) static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ {
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_vif *avp = (void *)vif->drv_priv;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc); 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); ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);

View file

@ -19,7 +19,6 @@
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h> #include <linux/module.h>
#include "ath9k.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) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{ {
struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_hw *ah = (struct ath_hw *) common->ah;
struct ath9k_platform_data *pdata = sc->dev->platform_data;
if (pdata && !pdata->use_eeprom) { common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
ath_err(common,
"%s: eeprom read failed, offset %08x is out of range\n",
__func__, off);
}
*data = pdata->eeprom_data[off]; if (!ath9k_hw_wait(ah,
} else { AR_EEPROM_STATUS_DATA,
struct ath_hw *ah = (struct ath_hw *) common->ah; AR_EEPROM_STATUS_DATA_BUSY |
AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
common->ops->read(ah, AR5416_EEPROM_OFFSET + AH_WAIT_TIMEOUT)) {
(off << AR5416_EEPROM_S)); return false;
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);
} }
*data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
AR_EEPROM_STATUS_DATA_VAL);
return true; 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; 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) static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
{ {
wcn36xx_dbg(WCN36XX_DBG_DXE, wcn36xx_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_write_register: addr=%x, data=%x\n", "wcn36xx_dxe_write_register: addr=%x, data=%x\n",
addr, data); 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) 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_dbg(WCN36XX_DBG_DXE,
"wcn36xx_dxe_read_register: addr=%x, data=%x\n", "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; reg_data = WCN36XX_DXE_REG_RESET;
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data); wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
/* Setting interrupt path */ /* Select channels for rx avail and xfer done interrupts... */
reg_data = WCN36XX_DXE_CCU_INT; reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data); 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 */ /* Init descriptors for TX LOW channel */

View file

@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2
*/ */
/* DXE registers */ /* DXE registers */
#define WCN36XX_DXE_MEM_REG 0x202000 #define WCN36XX_DXE_MEM_REG 0
#define WCN36XX_DXE_CCU_INT 0xA0011 #define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
#define WCN36XX_DXE_REG_CCU_INT_3660 0x200b10 #define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
#define WCN36XX_DXE_REG_CCU_INT_3680 0x2050dc
/* TODO This must calculated properly but not hardcoded */ /* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44 #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 /* Update scan params - sent from host to PNO to be used during PNO
* scanningx */ * scanningx */
struct update_scan_params_req_ex { struct wcn36xx_hal_update_scan_params_req_ex {
struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_msg_header header;
@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex {
/* Cb State */ /* Cb State */
enum phy_chan_bond_state state; enum phy_chan_bond_state state;
}; } __packed;
/* Update scan params - sent from host to PNO to be used during PNO /* Update scan params - sent from host to PNO to be used during PNO
* scanningx */ * scanningx */

View file

@ -19,6 +19,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include "wcn36xx.h" #include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask; 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) static int wcn36xx_start(struct ieee80211_hw *hw)
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
@ -324,9 +315,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_feat_caps_info(wcn); 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 */ /* DMA channel initialization */
ret = wcn36xx_dxe_init(wcn); ret = wcn36xx_dxe_init(wcn);
if (ret) { if (ret) {
@ -1064,7 +1052,11 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
struct platform_device *pdev) struct platform_device *pdev)
{ {
struct device_node *mmio_node;
struct resource *res; struct resource *res;
int index;
int ret;
/* Set TX IRQ */ /* Set TX IRQ */
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"wcnss_wlantx_irq"); "wcnss_wlantx_irq");
@ -1083,19 +1075,40 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
} }
wcn->rx_irq = res->start; wcn->rx_irq = res->start;
/* Map the memory */ mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, if (!mmio_node) {
"wcnss_mmio"); wcn36xx_err("failed to acquire qcom,mmio reference\n");
if (!res) { return -EINVAL;
wcn36xx_err("failed to get mmio\n");
return -ENOENT;
} }
wcn->mmio = ioremap(res->start, resource_size(res));
if (!wcn->mmio) { wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
wcn36xx_err("failed to map io memory\n");
return -ENOMEM; /* 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; 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) static int wcn36xx_probe(struct platform_device *pdev)
@ -1138,7 +1151,8 @@ static int wcn36xx_probe(struct platform_device *pdev)
return 0; return 0;
out_unmap: out_unmap:
iounmap(wcn->mmio); iounmap(wcn->ccu_base);
iounmap(wcn->dxe_base);
out_wq: out_wq:
ieee80211_free_hw(hw); ieee80211_free_hw(hw);
out_err: out_err:
@ -1154,7 +1168,8 @@ static int wcn36xx_remove(struct platform_device *pdev)
mutex_destroy(&wcn->hal_mutex); mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
iounmap(wcn->mmio); iounmap(wcn->dxe_base);
iounmap(wcn->ccu_base);
ieee80211_free_hw(hw); ieee80211_free_hw(hw);
return 0; return 0;

View file

@ -674,22 +674,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
return 0; 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; int ret = 0;
mutex_lock(&wcn->hal_mutex); mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ); INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
msg_body.dot11d_enabled = 0; msg_body.dot11d_enabled = false;
msg_body.dot11d_resolved = 0; msg_body.dot11d_resolved = true;
msg_body.channel_count = 26;
msg_body.channel_count = channel_count;
memcpy(msg_body.channels, channels, channel_count);
msg_body.active_min_ch_time = 60; msg_body.active_min_ch_time = 60;
msg_body.active_max_ch_time = 120; msg_body.active_max_ch_time = 120;
msg_body.passive_min_ch_time = 60; msg_body.passive_min_ch_time = 60;
msg_body.passive_max_ch_time = 110; 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); 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_COEX_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_OTA_TX_COMPL_IND: case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND: case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL); msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
if (!msg_ind) 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:
/* /*
* FIXME: Do something smarter then just * FIXME: Do something smarter then just
* printing an error. * printing an error.
@ -2245,10 +2243,14 @@ nomem:
msg_header->msg_type); msg_header->msg_type);
break; 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); list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work); 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"); wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
break; break;
default: default:
@ -2262,8 +2264,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
container_of(work, struct wcn36xx, hal_ind_work); container_of(work, struct wcn36xx, hal_ind_work);
struct wcn36xx_hal_msg_header *msg_header; struct wcn36xx_hal_msg_header *msg_header;
struct wcn36xx_hal_ind_msg *hal_ind_msg; 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, hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
struct wcn36xx_hal_ind_msg, struct wcn36xx_hal_ind_msg,
@ -2273,6 +2276,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
switch (msg_header->msg_type) { switch (msg_header->msg_type) {
case WCN36XX_HAL_COEX_IND: case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_DEL_BA_IND:
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
break; break;
case WCN36XX_HAL_OTA_TX_COMPL_IND: 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); msg_header->msg_type);
} }
list_del(wcn->hal_ind_queue.next); list_del(wcn->hal_ind_queue.next);
kfree(hal_ind_msg->msg); spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
kfree(hal_ind_msg); kfree(hal_ind_msg);
mutex_unlock(&wcn->hal_ind_mutex);
} }
int wcn36xx_smd_open(struct wcn36xx *wcn) 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_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
INIT_LIST_HEAD(&wcn->hal_ind_queue); 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); ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
if (ret) { if (ret) {
@ -2330,5 +2333,4 @@ void wcn36xx_smd_close(struct wcn36xx *wcn)
{ {
wcn->ctrl_ops->close(); wcn->ctrl_ops->close();
destroy_workqueue(wcn->hal_ind_wq); 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 wcn36xx_hal_ind_msg {
struct list_head list; struct list_head list;
u8 *msg;
size_t msg_len; size_t msg_len;
u8 msg[];
}; };
struct wcn36xx; 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_end_scan(struct wcn36xx *wcn);
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
enum wcn36xx_hal_sys_mode mode); 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_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_self(struct wcn36xx *wcn, u8 *addr);
int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index); int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);

View file

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

View file

@ -726,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
return -ENOMEM; return -ENOMEM;
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
glom_skb); glom_skb);
if (err) if (err) {
brcmu_pkt_buf_free_skb(glom_skb);
goto done; goto done;
}
skb_queue_walk(pktq, skb) { skb_queue_walk(pktq, skb) {
memcpy(skb->data, glom_skb->data, skb->len); 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); brcmf_err("SET SSID error (%d)\n", err);
goto exit; 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"); brcmf_dbg(TRACE, "AP mode configuration complete\n");
} else if (dev_role == NL80211_IFTYPE_P2P_GO) { } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); 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; 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)); memset(&join_params, 0, sizeof(join_params));
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, sizeof(join_params)); &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) void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
{ {
struct brcmf_fws_info *fws = drvr->fws; struct brcmf_fws_info *fws = drvr->fws;
struct brcmf_if *ifp;
int i;
fws->bus_flow_blocked = flow_blocked; if (fws->avoid_queueing) {
if (!flow_blocked) for (i = 0; i < BRCMF_MAX_IFS; i++) {
brcmf_fws_schedule_deq(fws); ifp = drvr->iflist[i];
else if (!ifp || !ifp->ndev)
fws->stats.bus_flow_block++; 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; goto err;
} }
/* Allow full data communication using DPC from now on. */
brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
bcmerror = 0;
err: err:
brcmf_sdio_clkctl(bus, CLK_SDONLY, false); brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
sdio_release_host(bus->sdiodev->func[1]); sdio_release_host(bus->sdiodev->func[1]);
@ -4046,6 +4042,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
} }
if (err == 0) { 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); err = brcmf_sdiod_intr_register(sdiodev);
if (err != 0) if (err != 0)
brcmf_err("intr register failed:%d\n", err); 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, pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
DMA_FROM_DEVICE); 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; return false;
}
/* save the free packet pointer */ /* save the free packet pointer */
di->rxp[rxout] = p; 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, brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
u16 chanspec) u16 chanspec)
{ {
struct tx_power power; struct tx_power power = { };
u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
/* Clear previous settings */ /* Clear previous settings */

View file

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

View file

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

View file

@ -55,7 +55,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 21 #define IWL9000_UCODE_API_MAX 24
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL9000_UCODE_API_MIN 16 #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, static int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout) bool enabled, int timeout)
{ {
struct lbs_private *priv = wiphy_priv(wiphy); 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); mwifiex_set_uap_rates(bss_cfg, params);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) { if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
mwifiex_dbg(priv->adapter, ERROR, mwifiex_dbg(priv->adapter, ERROR,
"Failed to parse secuirty parameters!\n"); "Failed to parse secuirty parameters!\n");
return -1; goto out;
} }
mwifiex_set_ht_params(priv, bss_cfg, params); 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)) { if (mwifiex_11h_activate(priv, false)) {
mwifiex_dbg(priv->adapter, ERROR, mwifiex_dbg(priv->adapter, ERROR,
"Failed to disable 11h extensions!!"); "Failed to disable 11h extensions!!");
return -1; goto out;
} }
priv->state_11h.is_11h_active = false; 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)) { if (mwifiex_config_start_uap(priv, bss_cfg)) {
mwifiex_dbg(priv->adapter, ERROR, mwifiex_dbg(priv->adapter, ERROR,
"Failed to start AP\n"); "Failed to start AP\n");
kfree(bss_cfg); goto out;
return -1;
} }
if (mwifiex_set_mgmt_ies(priv, &params->beacon)) if (mwifiex_set_mgmt_ies(priv, &params->beacon))
return -1; goto out;
if (!netif_carrier_ok(priv->netdev)) if (!netif_carrier_ok(priv->netdev))
netif_carrier_on(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)); memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg));
kfree(bss_cfg); kfree(bss_cfg);
return 0; return 0;
out:
kfree(bss_cfg);
return -1;
} }
/* /*

View file

@ -343,16 +343,16 @@ enum {
}; };
struct mwifiex_ds_reg_rw { struct mwifiex_ds_reg_rw {
__le32 type; u32 type;
__le32 offset; u32 offset;
__le32 value; u32 value;
}; };
#define MAX_EEPROM_DATA 256 #define MAX_EEPROM_DATA 256
struct mwifiex_ds_read_eeprom { struct mwifiex_ds_read_eeprom {
__le16 offset; u16 offset;
__le16 byte_count; u16 byte_count;
u8 value[MAX_EEPROM_DATA]; 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, if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
MWIFIEX_PCIE)) { MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__); pr_err("%s failed\n", __func__);
kfree(card);
return -1; return -1;
} }
@ -1617,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
pkt_len = *((__le16 *)skb->data); pkt_len = *((__le16 *)skb->data);
rx_len = le16_to_cpu(pkt_len); rx_len = le16_to_cpu(pkt_len);
skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
skb_trim(skb, rx_len); skb_trim(skb, rx_len);
skb_pull(skb, INTF_HEADER_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, mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n", "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); "MRVL_PCIE", &card->share_irq_ctx);
if (ret) { if (ret) {
pr_err("request_irq failed: ret=%d\n", ret); pr_err("request_irq failed: ret=%d\n", ret);
adapter->card = NULL;
return -1; 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); cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
mac_reg = &cmd->params.mac_reg; mac_reg = &cmd->params.mac_reg;
mac_reg->action = cpu_to_le16(cmd_action); mac_reg->action = cpu_to_le16(cmd_action);
mac_reg->offset = mac_reg->offset = cpu_to_le16((u16) reg_rw->offset);
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); mac_reg->value = cpu_to_le32(reg_rw->value);
mac_reg->value = reg_rw->value;
break; break;
} }
case HostCmd_CMD_BBP_REG_ACCESS: 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); cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
bbp_reg = &cmd->params.bbp_reg; bbp_reg = &cmd->params.bbp_reg;
bbp_reg->action = cpu_to_le16(cmd_action); bbp_reg->action = cpu_to_le16(cmd_action);
bbp_reg->offset = bbp_reg->offset = cpu_to_le16((u16) reg_rw->offset);
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); bbp_reg->value = (u8) reg_rw->value;
bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
break; break;
} }
case HostCmd_CMD_RF_REG_ACCESS: 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); cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
rf_reg = &cmd->params.rf_reg; rf_reg = &cmd->params.rf_reg;
rf_reg->action = cpu_to_le16(cmd_action); rf_reg->action = cpu_to_le16(cmd_action);
rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); rf_reg->offset = cpu_to_le16((u16) reg_rw->offset);
rf_reg->value = (u8) le32_to_cpu(reg_rw->value); rf_reg->value = (u8) reg_rw->value;
break; break;
} }
case HostCmd_CMD_PMIC_REG_ACCESS: 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); cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
pmic_reg = &cmd->params.pmic_reg; pmic_reg = &cmd->params.pmic_reg;
pmic_reg->action = cpu_to_le16(cmd_action); pmic_reg->action = cpu_to_le16(cmd_action);
pmic_reg->offset = pmic_reg->offset = cpu_to_le16((u16) reg_rw->offset);
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); pmic_reg->value = (u8) reg_rw->value;
pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
break; break;
} }
case HostCmd_CMD_CAU_REG_ACCESS: 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); cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
cau_reg = &cmd->params.rf_reg; cau_reg = &cmd->params.rf_reg;
cau_reg->action = cpu_to_le16(cmd_action); cau_reg->action = cpu_to_le16(cmd_action);
cau_reg->offset = cau_reg->offset = cpu_to_le16((u16) reg_rw->offset);
cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); cau_reg->value = (u8) reg_rw->value;
cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
break; break;
} }
case HostCmd_CMD_802_11_EEPROM_ACCESS: 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->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
cmd_eeprom->action = cpu_to_le16(cmd_action); cmd_eeprom->action = cpu_to_le16(cmd_action);
cmd_eeprom->offset = rd_eeprom->offset; cmd_eeprom->offset = cpu_to_le16(rd_eeprom->offset);
cmd_eeprom->byte_count = rd_eeprom->byte_count; cmd_eeprom->byte_count = cpu_to_le16(rd_eeprom->byte_count);
cmd_eeprom->value = 0; cmd_eeprom->value = 0;
break; break;
} }

View file

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

View file

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

View file

@ -12,4 +12,4 @@ rtl8188ee-objs := \
obj-$(CONFIG_RTL8188EE) += rtl8188ee.o 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; int_fw_status->counters.tx_voice_released_blks;
fw_status->counters.tx_last_rate = fw_status->counters.tx_last_rate =
int_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); 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, .max = 1,
.types = BIT(NL80211_IFTYPE_AP) | .types = BIT(NL80211_IFTYPE_AP)
BIT(NL80211_IFTYPE_P2P_GO) | | BIT(NL80211_IFTYPE_P2P_GO)
BIT(NL80211_IFTYPE_P2P_CLIENT), | BIT(NL80211_IFTYPE_P2P_CLIENT)
#ifdef CONFIG_MAC80211_MESH
| BIT(NL80211_IFTYPE_MESH_POINT)
#endif
}, },
{ {
.max = 1, .max = 1,
@ -1836,6 +1843,12 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
.max = 2, .max = 2,
.types = BIT(NL80211_IFTYPE_AP), .types = BIT(NL80211_IFTYPE_AP),
}, },
#ifdef CONFIG_MAC80211_MESH
{
.max = 1,
.types = BIT(NL80211_IFTYPE_MESH_POINT),
},
#endif
{ {
.max = 1, .max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE), .types = BIT(NL80211_IFTYPE_P2P_DEVICE),

View file

@ -30,9 +30,9 @@
static static
void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, 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) { if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
wl1271_error("last Tx rate invalid: %d", fw_rate); 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; struct sk_buff *skb;
int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK; int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
bool tx_success; bool tx_success;
struct wl1271_tx_hw_descr *tx_desc;
/* check for id legality */ /* check for id legality */
if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 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]; skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
tx_desc = (struct wl1271_tx_hw_descr *)skb->data;
if (wl12xx_is_dummy_packet(wl, skb)) { if (wl12xx_is_dummy_packet(wl, skb)) {
wl1271_free_tx_id(wl, id); 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 * the info->status structures
*/ */
wl18xx_get_last_tx_rate(wl, info->control.vif, 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.rates[0].count = 1; /* no data about retries */
info->status.ack_signal = -1; 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 *status_priv =
(struct wl18xx_fw_status_priv *)wl->fw_status->priv; (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
struct wl18xx_priv *priv = wl->priv; struct wl18xx_priv *priv = wl->priv;
u8 i; u8 i, hlid;
/* nothing to do here */ /* nothing to do here */
if (priv->last_fw_rls_idx == status_priv->fw_release_idx) if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
return; 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 */ /* freed Tx descriptors */
wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d", wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
priv->last_fw_rls_idx, status_priv->fw_release_idx); priv->last_fw_rls_idx, status_priv->fw_release_idx);

View file

@ -29,7 +29,7 @@
#define WL18XX_IFTYPE_VER 9 #define WL18XX_IFTYPE_VER 9
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_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 #define WL18XX_CMD_MAX_SIZE 740
@ -125,7 +125,11 @@ struct wl18xx_fw_packet_counters {
/* Tx rate of the last transmitted packet */ /* Tx rate of the last transmitted packet */
u8 tx_last_rate; 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; } __packed;
/* FW status registers */ /* FW status registers */

View file

@ -105,6 +105,7 @@ enum wl12xx_role {
WL1271_ROLE_DEVICE, WL1271_ROLE_DEVICE,
WL1271_ROLE_P2P_CL, WL1271_ROLE_P2P_CL,
WL1271_ROLE_P2P_GO, WL1271_ROLE_P2P_GO,
WL1271_ROLE_MESH_POINT,
WL12XX_INVALID_ROLE_TYPE = 0xff 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" wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
"Please use at least FW %s\n" "Please use at least FW %s\n"
"You can get the latest firmwares at:\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_CHIP], fw_ver[FW_VER_IF_TYPE],
fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
fw_ver[FW_VER_MINOR], min_fw_str); 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); wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
/* trying to use hidden SSID with an old hostapd version */ /* If MESH --> ssid_len is always 0 */
if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { if (!ieee80211_vif_is_mesh(vif)) {
wl1271_error("got a null SSID from beacon/bss"); /* trying to use hidden SSID with an old hostapd version */
ret = -EINVAL; if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
goto out; wl1271_error("got a null SSID from beacon/bss");
ret = -EINVAL;
goto out;
}
} }
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 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, struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
rc_update_work); rc_update_work);
struct wl1271 *wl = wlvif->wl; struct wl1271 *wl = wlvif->wl;
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
@ -231,8 +232,16 @@ static void wlcore_rc_update_work(struct work_struct *work)
if (ret < 0) if (ret < 0)
goto out; 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); wl1271_ps_elp_sleep(wl);
out: out:
mutex_unlock(&wl->mutex); 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) 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) { switch (wlvif->bss_type) {
case BSS_TYPE_AP_BSS: case BSS_TYPE_AP_BSS:
if (wlvif->p2p) if (wlvif->p2p)
return WL1271_ROLE_P2P_GO; return WL1271_ROLE_P2P_GO;
else if (ieee80211_vif_is_mesh(vif))
return WL1271_ROLE_MESH_POINT;
else else
return WL1271_ROLE_AP; return WL1271_ROLE_AP;
@ -2198,6 +2211,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wlvif->p2p = 1; wlvif->p2p = 1;
/* fall-through */ /* fall-through */
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
wlvif->bss_type = BSS_TYPE_AP_BSS; wlvif->bss_type = BSS_TYPE_AP_BSS;
break; break;
default: default:
@ -4131,9 +4145,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif); /* No need to set probe resp template for mesh */
if (ret < 0) if (!ieee80211_vif_is_mesh(vif)) {
goto out; 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); ret = wlcore_set_beacon_template(wl, vif, true);
if (ret < 0) if (ret < 0)
@ -4967,6 +4986,7 @@ static int wl12xx_sta_add(struct wl1271 *wl,
return ret; return ret;
wl_sta = (struct wl1271_station *)sta->drv_priv; wl_sta = (struct wl1271_station *)sta->drv_priv;
wl_sta->wl = wl;
hlid = wl_sta->hlid; hlid = wl_sta->hlid;
ret = wl12xx_cmd_add_peer(wl, wlvif, 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 */ /* this callback is atomic, so schedule a new work */
wlvif->rc_update_bw = sta->bandwidth; 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); ieee80211_queue_work(hw, &wlvif->rc_update_work);
} }
@ -5679,6 +5700,16 @@ out:
mutex_unlock(&wl->mutex); 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) static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
@ -5879,6 +5910,7 @@ static const struct ieee80211_ops wl1271_ops = {
.switch_vif_chanctx = wlcore_op_switch_vif_chanctx, .switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update, .sta_rc_update = wlcore_op_sta_rc_update,
.sta_statistics = wlcore_op_sta_statistics, .sta_statistics = wlcore_op_sta_statistics,
.get_expected_throughput = wlcore_op_get_expected_throughput,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd) 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_AP) |
BIT(NL80211_IFTYPE_P2P_DEVICE) | BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_P2P_GO); BIT(NL80211_IFTYPE_P2P_GO);
wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_scan_ssids = 1;
wl->hw->wiphy->max_sched_scan_ssids = 16; wl->hw->wiphy->max_sched_scan_ssids = 16;
wl->hw->wiphy->max_match_sets = 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; enum wl_rx_buf_align rx_align;
int ret = 0; 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) { while (drv_rx_counter != fw_rx_counter) {
buf_size = 0; buf_size = 0;
rx_counter = drv_rx_counter; rx_counter = drv_rx_counter;

View file

@ -70,16 +70,30 @@
#define WSPI_MAX_CHUNK_SIZE 4092 #define WSPI_MAX_CHUNK_SIZE 4092
/* /*
* only support SPI for 12xx - this code should be reworked when 18xx * wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to
* support is introduced * (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 */ /* Maximum number of SPI write chunks */
#define WSPI_MAX_NUM_OF_CHUNKS \ #define WSPI_MAX_NUM_OF_CHUNKS \
((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) ((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 wl12xx_spi_glue {
struct device *dev; struct device *dev;
struct platform_device *core; 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 wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct spi_transfer t; struct spi_transfer t;
struct spi_message m; struct spi_message m;
struct spi_device *spi = to_spi_device(glue->dev);
u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); u8 *cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) { if (!cmd) {
@ -151,6 +166,7 @@ static void wl12xx_spi_init(struct device *child)
cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY; cmd[6] |= WSPI_INIT_CMD_EN_FIXEDBUSY;
cmd[7] = crc7_be(0, cmd+2, WSPI_INIT_CMD_CRC_LEN) | WSPI_INIT_CMD_END; 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 * The above is the logical order; it must actually be stored
* in the buffer byte-swapped. * in the buffer byte-swapped.
@ -163,6 +179,28 @@ static void wl12xx_spi_init(struct device *child)
spi_message_add_tail(&t, &m); spi_message_add_tail(&t, &m);
spi_sync(to_spi_device(glue->dev), &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); kfree(cmd);
} }
@ -270,22 +308,25 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
return 0; return 0;
} }
static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, static int __wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
/* SPI write buffers - 2 for each chunk */ struct spi_transfer *t;
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_message m; struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */
u32 *cmd; u32 *cmd;
u32 chunk_len; u32 chunk_len;
int i; 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); WARN_ON(len > SPI_AGGR_BUFFER_SIZE);
spi_message_init(&m); spi_message_init(&m);
memset(t, 0, sizeof(t));
cmd = &commands[0]; cmd = &commands[0];
i = 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); spi_sync(to_spi_device(glue->dev), &m);
kfree(t);
return 0; 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 * wl12xx_spi_set_power - power on/off the wl12xx unit
* @child: wl12xx device handle. * @child: wl12xx device handle.
@ -349,17 +407,38 @@ static int wl12xx_spi_set_power(struct device *child, bool enable)
return ret; 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 = { static struct wl1271_if_operations spi_ops = {
.read = wl12xx_spi_raw_read, .read = wl12xx_spi_raw_read,
.write = wl12xx_spi_raw_write, .write = wl12xx_spi_raw_write,
.reset = wl12xx_spi_reset, .reset = wl12xx_spi_reset,
.init = wl12xx_spi_init, .init = wl12xx_spi_init,
.power = wl12xx_spi_set_power, .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[] = { 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); 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 wlcore_platdev_data *pdev_data)
{ {
struct device_node *dt_node = spi->dev.of_node; 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)) if (of_find_property(dt_node, "clock-xtal", NULL))
pdev_data->ref_clock_xtal = true; pdev_data->ref_clock_xtal = true;
ret = of_property_read_u32(dt_node, "ref-clock-frequency", /* optional clock frequency params */
&pdev_data->ref_clock_freq); of_property_read_u32(dt_node, "ref-clock-frequency",
if (ret) { &pdev_data->ref_clock_freq);
dev_err(glue->dev, of_property_read_u32(dt_node, "tcxo-clock-frequency",
"can't get reference clock frequency (%d)\n", ret); &pdev_data->tcxo_clock_freq);
return ret;
}
return 0; return 0;
} }
@ -437,7 +522,8 @@ static int wl1271_probe(struct spi_device *spi)
return ret; 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) { if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n"); dev_err(glue->dev, "can't allocate platform_device\n");
return -ENOMEM; return -ENOMEM;

View file

@ -171,6 +171,12 @@ struct wl_fw_status {
/* Tx rate of the last transmitted packet */ /* Tx rate of the last transmitted packet */
u8 tx_last_rate; 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; } counters;
u32 log_start_addr; u32 log_start_addr;
@ -273,6 +279,12 @@ struct wl1271_link {
/* bitmap of TIDs where RX BA sessions are active for this link */ /* bitmap of TIDs where RX BA sessions are active for this link */
u8 ba_bitmap; 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 */ /* The wlvif this link belongs to. Might be null for global links */
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
@ -335,6 +347,7 @@ struct wl1271_station {
* Used in both AP and STA mode. * Used in both AP and STA mode.
*/ */
u64 total_freed_pkts; u64 total_freed_pkts;
struct wl1271 *wl;
}; };
struct wl12xx_vif { struct wl12xx_vif {
@ -472,6 +485,7 @@ struct wl12xx_vif {
/* update rate conrol */ /* update rate conrol */
enum ieee80211_sta_rx_bandwidth rc_update_bw; enum ieee80211_sta_rx_bandwidth rc_update_bw;
struct ieee80211_sta_ht_cap rc_ht_cap;
struct work_struct rc_update_work; struct work_struct rc_update_work;
/* /*

View file

@ -40,6 +40,7 @@ struct ath9k_platform_data {
bool tx_gain_buffalo; bool tx_gain_buffalo;
bool disable_2ghz; bool disable_2ghz;
bool disable_5ghz; bool disable_5ghz;
bool led_active_high;
int (*get_mac_revision)(void); int (*get_mac_revision)(void);
int (*external_reset)(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_MASK 0x1ff00000
#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 #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. */ /* BCM4331 ChipControl numbers. */
#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */ #define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */
#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */ #define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */