aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-10-30 20:38:24 +0900
committerDavid S. Miller <davem@davemloft.net>2015-10-30 20:38:24 +0900
commita493bcf8d6caf28f062c5f8f2ba486fdbf1ae899 (patch)
tree66d31fa2f1296caee8f46ea019d032c1bac3b111
parentswitchdev: fix: pass correct obj size when deferring obj add (diff)
parentMerge ath-next from ath.git (diff)
downloadlinux-dev-a493bcf8d6caf28f062c5f8f2ba486fdbf1ae899.tar.xz
linux-dev-a493bcf8d6caf28f062c5f8f2ba486fdbf1ae899.zip
Merge tag 'wireless-drivers-next-for-davem-2015-10-29' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== iwlwifi * bug fix for TDLS * fixes and cleanups in scan * support of several scan plans * improvements in FTM * fixes in FW API * improvements in the failure paths when the bus is dead * other various small things here and there ath10k * add QCA9377 support * fw_stats support for 10.4 firmware ath6kl * report antenna configuration to user space * implement ethtool stats ssb * add Kconfig SSB_HOST_SOC for compiling SoC related code * move functions specific to SoC hosted bus to separated file * pick PCMCIA host code support from b43 driver ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/mips/bcm47xx/Kconfig1
-rw-r--r--drivers/net/wireless/airo.c77
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c57
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h16
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c346
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c71
-rw-r--r--drivers/net/wireless/ath/ath10k/targaddrs.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.c202
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h25
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c248
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h148
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c143
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c55
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-debug.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h18
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c61
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.h1
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c30
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h4
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c20
-rw-r--r--drivers/net/wireless/b43/Kconfig20
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/main.c9
-rw-r--r--drivers/net/wireless/b43/pcmcia.c145
-rw-r--r--drivers/net/wireless/b43/pcmcia.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c25
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c67
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c41
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c120
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c9
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c11
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c10
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c8
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c7
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c1
-rw-r--r--drivers/ssb/Kconfig9
-rw-r--r--drivers/ssb/Makefile3
-rw-r--r--drivers/ssb/bridge_pcmcia_80211.c128
-rw-r--r--drivers/ssb/host_soc.c173
-rw-r--r--drivers/ssb/main.c172
-rw-r--r--drivers/ssb/ssb_private.h16
63 files changed, 1843 insertions, 889 deletions
diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig
index 51ed599cc894..e970fd9cf769 100644
--- a/arch/mips/bcm47xx/Kconfig
+++ b/arch/mips/bcm47xx/Kconfig
@@ -4,6 +4,7 @@ config BCM47XX_SSB
bool "SSB Support for Broadcom BCM47XX"
select SYS_HAS_CPU_BMIPS32_3300
select SSB
+ select SSB_HOST_SOC
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
select SSB_EMBEDDED
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 8ae838d96a9e..17c40f06f13e 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1231,7 +1231,7 @@ struct airo_info {
dma_addr_t shared_dma;
pm_message_t power;
SsidRid *SSID;
- APListRid *APList;
+ APListRid APList;
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
char proc_name[IFNAMSIZ];
@@ -1848,11 +1848,6 @@ static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock)
return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
}
-static int readAPListRid(struct airo_info *ai, APListRid *aplr)
-{
- return PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
-}
-
static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock)
{
return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
@@ -2413,7 +2408,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
kfree(ai->flash);
kfree(ai->rssi);
- kfree(ai->APList);
kfree(ai->SSID);
if (freeres) {
/* PCMCIA frees this stuff, so only for PCI and ISA */
@@ -2809,6 +2803,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
init_waitqueue_head (&ai->thr_wait);
ai->tfm = NULL;
add_airo_dev(ai);
+ ai->APList.len = cpu_to_le16(sizeof(struct APListRid));
if (airo_networks_allocate (ai))
goto err_out_free;
@@ -3042,6 +3037,11 @@ static void airo_process_scan_results (struct airo_info *ai) {
}
out:
+ /* write APList back (we cleared it in airo_set_scan) */
+ disable_MAC(ai, 2);
+ writeAPListRid(ai, &ai->APList, 0);
+ enable_MAC(ai, 0);
+
ai->scan_timeout = 0;
clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
up(&ai->sem);
@@ -3613,17 +3613,18 @@ static void disable_MAC( struct airo_info *ai, int lock ) {
Cmd cmd;
Resp rsp;
- if (lock && down_interruptible(&ai->sem))
+ if (lock == 1 && down_interruptible(&ai->sem))
return;
if (test_bit(FLAG_ENABLED, &ai->flags)) {
- netif_carrier_off(ai->dev);
+ if (lock != 2) /* lock == 2 means don't disable carrier */
+ netif_carrier_off(ai->dev);
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
issuecommand(ai, &cmd, &rsp);
clear_bit(FLAG_ENABLED, &ai->flags);
}
- if (lock)
+ if (lock == 1)
up(&ai->sem);
}
@@ -3852,8 +3853,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
tdsRssiRid rssi_rid;
CapabilityRid cap_rid;
- kfree(ai->APList);
- ai->APList = NULL;
kfree(ai->SSID);
ai->SSID = NULL;
// general configuration (read/modify/write)
@@ -5130,31 +5129,31 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
struct proc_data *data = file->private_data;
struct net_device *dev = PDE_DATA(inode);
struct airo_info *ai = dev->ml_priv;
- APListRid APList_rid;
+ APListRid *APList_rid = &ai->APList;
int i;
if ( !data->writelen ) return;
- memset( &APList_rid, 0, sizeof(APList_rid) );
- APList_rid.len = cpu_to_le16(sizeof(APList_rid));
+ memset(APList_rid, 0, sizeof(*APList_rid));
+ APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
int j;
for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
switch(j%3) {
case 0:
- APList_rid.ap[i][j/3]=
+ APList_rid->ap[i][j/3]=
hex_to_bin(data->wbuffer[j+i*6*3])<<4;
break;
case 1:
- APList_rid.ap[i][j/3]|=
+ APList_rid->ap[i][j/3]|=
hex_to_bin(data->wbuffer[j+i*6*3]);
break;
}
}
}
disable_MAC(ai, 1);
- writeAPListRid(ai, &APList_rid, 1);
+ writeAPListRid(ai, APList_rid, 1);
enable_MAC(ai, 1);
}
@@ -5408,7 +5407,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
struct airo_info *ai = dev->ml_priv;
int i;
char *ptr;
- APListRid APList_rid;
+ APListRid *APList_rid = &ai->APList;
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5426,13 +5425,12 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
}
data->on_close = proc_APList_on_close;
- readAPListRid(ai, &APList_rid);
ptr = data->rbuffer;
for( i = 0; i < 4; i++ ) {
// We end when we find a zero MAC
- if ( !*(int*)APList_rid.ap[i] &&
- !*(int*)&APList_rid.ap[i][2]) break;
- ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]);
+ if ( !*(int*)APList_rid->ap[i] &&
+ !*(int*)&APList_rid->ap[i][2]) break;
+ ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]);
}
if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
@@ -5596,15 +5594,10 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
Cmd cmd;
Resp rsp;
- if (!ai->APList)
- ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL);
- if (!ai->APList)
- return -ENOMEM;
if (!ai->SSID)
ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
if (!ai->SSID)
return -ENOMEM;
- readAPListRid(ai, ai->APList);
readSsidRid(ai, ai->SSID);
memset(&cmd, 0, sizeof(cmd));
/* the lock will be released at the end of the resume callback */
@@ -5652,11 +5645,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
kfree(ai->SSID);
ai->SSID = NULL;
}
- if (ai->APList) {
- writeAPListRid(ai, ai->APList, 0);
- kfree(ai->APList);
- ai->APList = NULL;
- }
+ writeAPListRid(ai, &ai->APList, 0);
writeConfigRid(ai, 0);
enable_MAC(ai, 0);
ai->power = PMSG_ON;
@@ -5954,7 +5943,7 @@ static int airo_set_wap(struct net_device *dev,
struct airo_info *local = dev->ml_priv;
Cmd cmd;
Resp rsp;
- APListRid APList_rid;
+ APListRid *APList_rid = &local->APList;
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;
@@ -5967,11 +5956,11 @@ static int airo_set_wap(struct net_device *dev,
issuecommand(local, &cmd, &rsp);
up(&local->sem);
} else {
- memset(&APList_rid, 0, sizeof(APList_rid));
- APList_rid.len = cpu_to_le16(sizeof(APList_rid));
- memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
+ memset(APList_rid, 0, sizeof(*APList_rid));
+ APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
+ memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN);
disable_MAC(local, 1);
- writeAPListRid(local, &APList_rid, 1);
+ writeAPListRid(local, APList_rid, 1);
enable_MAC(local, 1);
}
return 0;
@@ -7233,6 +7222,7 @@ static int airo_set_scan(struct net_device *dev,
Cmd cmd;
Resp rsp;
int wake = 0;
+ APListRid APList_rid_empty;
/* Note : you may have realised that, as this is a SET operation,
* this is privileged and therefore a normal user can't
@@ -7250,6 +7240,13 @@ static int airo_set_scan(struct net_device *dev,
if (ai->scan_timeout > 0)
goto out;
+ /* Clear APList as it affects scan results */
+ memset(&APList_rid_empty, 0, sizeof(APList_rid_empty));
+ APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty));
+ disable_MAC(ai, 2);
+ writeAPListRid(ai, &APList_rid_empty, 0);
+ enable_MAC(ai, 0);
+
/* Initiate a scan command */
ai->scan_timeout = RUN_AT(3*HZ);
memset(&cmd, 0, sizeof(cmd));
@@ -7505,10 +7502,8 @@ static int airo_config_commit(struct net_device *dev,
* parameters. It's now time to commit them in the card */
disable_MAC(local, 1);
if (test_bit (FLAG_RESET, &local->flags)) {
- APListRid APList_rid;
SsidRid SSID_rid;
- readAPListRid(local, &APList_rid);
readSsidRid(local, &SSID_rid);
if (test_bit(FLAG_MPI,&local->flags))
setup_card(local, dev->dev_addr, 1 );
@@ -7516,7 +7511,7 @@ static int airo_config_commit(struct net_device *dev,
reset_airo_card(dev);
disable_MAC(local, 1);
writeSsidRid(local, &SSID_rid, 1);
- writeAPListRid(local, &APList_rid, 1);
+ writeAPListRid(local, &local->APList, 1);
}
if (down_interruptible(&local->sem))
return -ERESTARTSYS;
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 84220c376308..edf3629288bc 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -274,7 +274,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
{
struct ath10k *ar = ce_state->ar;
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
- struct ce_desc *desc, *sdesc;
+ struct ce_desc *desc, sdesc;
unsigned int nentries_mask = src_ring->nentries_mask;
unsigned int sw_index = src_ring->sw_index;
unsigned int write_index = src_ring->write_index;
@@ -294,7 +294,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
desc = CE_SRC_RING_TO_DESC(src_ring->base_addr_owner_space,
write_index);
- sdesc = CE_SRC_RING_TO_DESC(src_ring->shadow_base, write_index);
desc_flags |= SM(transfer_id, CE_DESC_FLAGS_META_DATA);
@@ -303,11 +302,11 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
if (flags & CE_SEND_FLAG_BYTE_SWAP)
desc_flags |= CE_DESC_FLAGS_BYTE_SWAP;
- sdesc->addr = __cpu_to_le32(buffer);
- sdesc->nbytes = __cpu_to_le16(nbytes);
- sdesc->flags = __cpu_to_le16(desc_flags);
+ sdesc.addr = __cpu_to_le32(buffer);
+ sdesc.nbytes = __cpu_to_le16(nbytes);
+ sdesc.flags = __cpu_to_le16(desc_flags);
- *desc = *sdesc;
+ *desc = sdesc;
src_ring->per_transfer_context[write_index] = per_transfer_context;
@@ -579,17 +578,13 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
* The caller takes responsibility for any necessary locking.
*/
int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp)
+ void **per_transfer_contextp)
{
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
u32 ctrl_addr = ce_state->ctrl_addr;
struct ath10k *ar = ce_state->ar;
unsigned int nentries_mask = src_ring->nentries_mask;
unsigned int sw_index = src_ring->sw_index;
- struct ce_desc *sdesc, *sbase;
unsigned int read_index;
if (src_ring->hw_index == sw_index) {
@@ -614,15 +609,6 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
if (read_index == sw_index)
return -EIO;
- sbase = src_ring->shadow_base;
- sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index);
-
- /* Return data from completed source descriptor */
- *bufferp = __le32_to_cpu(sdesc->addr);
- *nbytesp = __le16_to_cpu(sdesc->nbytes);
- *transfer_idp = MS(__le16_to_cpu(sdesc->flags),
- CE_DESC_FLAGS_META_DATA);
-
if (per_transfer_contextp)
*per_transfer_contextp =
src_ring->per_transfer_context[sw_index];
@@ -697,10 +683,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
}
int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp)
+ void **per_transfer_contextp)
{
struct ath10k *ar = ce_state->ar;
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -708,9 +691,7 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
spin_lock_bh(&ar_pci->ce_lock);
ret = ath10k_ce_completed_send_next_nolock(ce_state,
- per_transfer_contextp,
- bufferp, nbytesp,
- transfer_idp);
+ per_transfer_contextp);
spin_unlock_bh(&ar_pci->ce_lock);
return ret;
@@ -940,27 +921,6 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
src_ring->base_addr_ce_space_unaligned,
CE_DESC_RING_ALIGN);
- /*
- * Also allocate a shadow src ring in regular
- * mem to use for faster access.
- */
- src_ring->shadow_base_unaligned =
- kmalloc((nentries * sizeof(struct ce_desc) +
- CE_DESC_RING_ALIGN), GFP_KERNEL);
- if (!src_ring->shadow_base_unaligned) {
- dma_free_coherent(ar->dev,
- (nentries * sizeof(struct ce_desc) +
- CE_DESC_RING_ALIGN),
- src_ring->base_addr_owner_space,
- src_ring->base_addr_ce_space);
- kfree(src_ring);
- return ERR_PTR(-ENOMEM);
- }
-
- src_ring->shadow_base = PTR_ALIGN(
- src_ring->shadow_base_unaligned,
- CE_DESC_RING_ALIGN);
-
return src_ring;
}
@@ -1139,7 +1099,6 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
if (ce_state->src_ring) {
- kfree(ce_state->src_ring->shadow_base_unaligned);
dma_free_coherent(ar->dev,
(ce_state->src_ring->nentries *
sizeof(struct ce_desc) +
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index dbb94fdb274b..47b734ce7ecf 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -100,12 +100,6 @@ struct ath10k_ce_ring {
/* CE address space */
u32 base_addr_ce_space;
- /*
- * Start of shadow copy of descriptors, within regular memory.
- * Aligned to descriptor-size boundary.
- */
- void *shadow_base_unaligned;
- struct ce_desc *shadow_base;
/* keep last */
void *per_transfer_context[0];
@@ -192,16 +186,10 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
* Pops 1 completed send buffer from Source ring.
*/
int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp);
+ void **per_transfer_contextp);
int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- void **per_transfer_contextp,
- u32 *bufferp,
- unsigned int *nbytesp,
- unsigned int *transfer_idp);
+ void **per_transfer_contextp);
/*==================CE Engine Initialization=======================*/
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 13de3617d5ab..aa9bd92ac4ed 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -137,6 +137,21 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
},
},
+ {
+ .id = QCA9377_HW_1_0_DEV_VERSION,
+ .name = "qca9377 hw1.0",
+ .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+ .uart_pin = 7,
+ .otp_exe_param = 0,
+ .fw = {
+ .dir = QCA9377_HW_1_0_FW_DIR,
+ .fw = QCA9377_HW_1_0_FW_FILE,
+ .otp = QCA9377_HW_1_0_OTP_FILE,
+ .board = QCA9377_HW_1_0_BOARD_DATA_FILE,
+ .board_size = QCA9377_BOARD_DATA_SZ,
+ .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+ },
+ },
};
static const char *const ath10k_core_fw_feature_str[] = {
@@ -151,6 +166,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad",
[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
+ [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -568,8 +584,8 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
}
break;
case ATH10K_FIRMWARE_MODE_UTF:
- data = ar->testmode.utf->data;
- data_len = ar->testmode.utf->size;
+ data = ar->testmode.utf_firmware_data;
+ data_len = ar->testmode.utf_firmware_len;
mode_name = "utf";
break;
default:
@@ -1900,6 +1916,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->hw_values = &qca988x_values;
break;
case ATH10K_HW_QCA6174:
+ case ATH10K_HW_QCA9377:
ar->regs = &qca6174_regs;
ar->hw_values = &qca6174_values;
break;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 7cc7cdd56c95..4a2301589902 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -214,6 +214,7 @@ struct ath10k_fw_stats_pdev {
s32 hw_queued;
s32 hw_reaped;
s32 underrun;
+ u32 hw_paused;
s32 tx_abort;
s32 mpdus_requed;
u32 tx_ko;
@@ -226,6 +227,16 @@ struct ath10k_fw_stats_pdev {
u32 pdev_resets;
u32 phy_underrun;
u32 txop_ovf;
+ u32 seq_posted;
+ u32 seq_failed_queueing;
+ u32 seq_completed;
+ u32 seq_restarted;
+ u32 mu_seq_posted;
+ u32 mpdus_sw_flush;
+ u32 mpdus_hw_filter;
+ u32 mpdus_truncated;
+ u32 mpdus_ack_failed;
+ u32 mpdus_expired;
/* PDEV RX stats */
s32 mid_ppdu_route_change;
@@ -242,6 +253,7 @@ struct ath10k_fw_stats_pdev {
s32 phy_errs;
s32 phy_err_drop;
s32 mpdu_errs;
+ s32 rx_ovfl_errs;
};
struct ath10k_fw_stats {
@@ -497,6 +509,9 @@ enum ath10k_fw_features {
*/
ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10,
+ /* Firmware Supports Adaptive CCA*/
+ ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -730,8 +745,6 @@ struct ath10k {
int num_started_vdevs;
/* Protected by conf-mutex */
- u8 supp_tx_chainmask;
- u8 supp_rx_chainmask;
u8 cfg_tx_chainmask;
u8 cfg_rx_chainmask;
@@ -814,9 +827,12 @@ struct ath10k {
struct {
/* protected by conf_mutex */
const struct firmware *utf;
+ char utf_version[32];
+ const void *utf_firmware_data;
+ size_t utf_firmware_len;
DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
enum ath10k_fw_wmi_op_version orig_wmi_op_version;
-
+ enum ath10k_fw_wmi_op_version op_version;
/* protected by data_lock */
bool utf_monitor;
} testmode;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 2d87737e35ff..39966a05c1cc 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -84,6 +84,15 @@ enum qca6174_chip_id_rev {
#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
+/* QCA9377 1.0 definitions */
+#define QCA9377_HW_1_0_DEV_VERSION 0x05020001
+#define QCA9377_HW_1_0_CHIP_ID_REV 0x1
+#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
+#define QCA9377_HW_1_0_FW_FILE "firmware.bin"
+#define QCA9377_HW_1_0_OTP_FILE "otp.bin"
+#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
+
#define ATH10K_FW_API2_FILE "firmware-2.bin"
#define ATH10K_FW_API3_FILE "firmware-3.bin"
@@ -94,6 +103,7 @@ enum qca6174_chip_id_rev {
#define ATH10K_FW_API5_FILE "firmware-5.bin"
#define ATH10K_FW_UTF_FILE "utf.bin"
+#define ATH10K_FW_UTF_API2_FILE "utf-2.bin"
/* includes also the null byte */
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
@@ -176,6 +186,7 @@ enum ath10k_hw_rev {
ATH10K_HW_QCA988X,
ATH10K_HW_QCA6174,
ATH10K_HW_QCA99X0,
+ ATH10K_HW_QCA9377,
};
struct ath10k_hw_regs {
@@ -228,6 +239,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
#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_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
/* Known pecularities:
* - raw appears in nwifi decap, raw and nwifi appear in ethernet decap
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 484c1a10372f..a7411fe90cc4 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3736,13 +3736,8 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
mutex_lock(&ar->conf_mutex);
- if (ar->cfg_tx_chainmask) {
- *tx_ant = ar->cfg_tx_chainmask;
- *rx_ant = ar->cfg_rx_chainmask;
- } else {
- *tx_ant = ar->supp_tx_chainmask;
- *rx_ant = ar->supp_rx_chainmask;
- }
+ *tx_ant = ar->cfg_tx_chainmask;
+ *rx_ant = ar->cfg_rx_chainmask;
mutex_unlock(&ar->conf_mutex);
@@ -3762,6 +3757,169 @@ static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
dbg, cm);
}
+static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
+{
+ int nsts = ar->vht_cap_info;
+
+ nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+ nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+
+ /* If firmware does not deliver to host number of space-time
+ * streams supported, assume it support up to 4 BF STS and return
+ * the value for VHT CAP: nsts-1)
+ */
+ if (nsts == 0)
+ return 3;
+
+ return nsts;
+}
+
+static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
+{
+ int sound_dim = ar->vht_cap_info;
+
+ sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+ sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+
+ /* If the sounding dimension is not advertised by the firmware,
+ * let's use a default value of 1
+ */
+ if (sound_dim == 0)
+ return 1;
+
+ return sound_dim;
+}
+
+static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
+{
+ struct ieee80211_sta_vht_cap vht_cap = {0};
+ u16 mcs_map;
+ u32 val;
+ int i;
+
+ vht_cap.vht_supported = 1;
+ vht_cap.cap = ar->vht_cap_info;
+
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
+ val = ath10k_mac_get_vht_cap_bf_sts(ar);
+ val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+ val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
+ if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
+ val = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
+ val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+ val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+
+ vht_cap.cap |= val;
+ }
+
+ mcs_map = 0;
+ for (i = 0; i < 8; i++) {
+ if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
+ mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
+ else
+ mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
+ }
+
+ vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+ vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+
+ return vht_cap;
+}
+
+static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
+{
+ int i;
+ struct ieee80211_sta_ht_cap ht_cap = {0};
+
+ if (!(ar->ht_cap_info & WMI_HT_CAP_ENABLED))
+ return ht_cap;
+
+ ht_cap.ht_supported = 1;
+ ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+ ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+ if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
+ ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+
+ if (ar->ht_cap_info & WMI_HT_CAP_HT40_SGI)
+ ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+
+ if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) {
+ u32 smps;
+
+ smps = WLAN_HT_CAP_SM_PS_DYNAMIC;
+ smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+ ht_cap.cap |= smps;
+ }
+
+ if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC)
+ ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
+
+ if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) {
+ u32 stbc;
+
+ stbc = ar->ht_cap_info;
+ stbc &= WMI_HT_CAP_RX_STBC;
+ stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT;
+ stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ stbc &= IEEE80211_HT_CAP_RX_STBC;
+
+ ht_cap.cap |= stbc;
+ }
+
+ if (ar->ht_cap_info & WMI_HT_CAP_LDPC)
+ ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+ if (ar->ht_cap_info & WMI_HT_CAP_L_SIG_TXOP_PROT)
+ ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
+
+ /* max AMSDU is implicitly taken from vht_cap_info */
+ if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK)
+ ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+ for (i = 0; i < ar->num_rf_chains; i++) {
+ if (ar->cfg_rx_chainmask & BIT(i))
+ ht_cap.mcs.rx_mask[i] = 0xFF;
+ }
+
+ ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+
+ return ht_cap;
+}
+
+static void ath10k_mac_setup_ht_vht_cap(struct ath10k *ar)
+{
+ struct ieee80211_supported_band *band;
+ struct ieee80211_sta_vht_cap vht_cap;
+ struct ieee80211_sta_ht_cap ht_cap;
+
+ ht_cap = ath10k_get_ht_cap(ar);
+ vht_cap = ath10k_create_vht_cap(ar);
+
+ if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) {
+ band = &ar->mac.sbands[IEEE80211_BAND_2GHZ];
+ band->ht_cap = ht_cap;
+
+ /* Enable the VHT support at 2.4 GHz */
+ band->vht_cap = vht_cap;
+ }
+ if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
+ band = &ar->mac.sbands[IEEE80211_BAND_5GHZ];
+ band->ht_cap = ht_cap;
+ band->vht_cap = vht_cap;
+ }
+}
+
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
{
int ret;
@@ -3794,6 +3952,9 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
return ret;
}
+ /* Reload HT/VHT capability */
+ ath10k_mac_setup_ht_vht_cap(ar);
+
return 0;
}
@@ -3884,9 +4045,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
}
}
- if (ar->cfg_tx_chainmask)
- __ath10k_set_antenna(ar, ar->cfg_tx_chainmask,
- ar->cfg_rx_chainmask);
+ __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
/*
* By default FW set ARP frames ac to voice (6). In that case ARP
@@ -3905,6 +4064,18 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
+ ar->fw_features)) {
+ ret = ath10k_wmi_pdev_enable_adaptive_cca(ar, 1,
+ WMI_CCA_DETECT_LEVEL_AUTO,
+ WMI_CCA_DETECT_MARGIN_AUTO);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable adaptive cca: %d\n",
+ ret);
+ goto err_core_stop;
+ }
+ }
+
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->ani_enable, 1);
if (ret) {
@@ -4063,39 +4234,6 @@ static u32 get_nss_from_chainmask(u16 chain_mask)
return 1;
}
-static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
-{
- int nsts = ar->vht_cap_info;
-
- nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
- nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
-
- /* If firmware does not deliver to host number of space-time
- * streams supported, assume it support up to 4 BF STS and return
- * the value for VHT CAP: nsts-1)
- * */
- if (nsts == 0)
- return 3;
-
- return nsts;
-}
-
-static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
-{
- int sound_dim = ar->vht_cap_info;
-
- sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
- sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
-
- /* If the sounding dimension is not advertised by the firmware,
- * let's use a default value of 1
- */
- if (sound_dim == 0)
- return 1;
-
- return sound_dim;
-}
-
static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif)
{
u32 value = 0;
@@ -6949,111 +7087,6 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
},
};
-static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
-{
- struct ieee80211_sta_vht_cap vht_cap = {0};
- u16 mcs_map;
- u32 val;
- int i;
-
- vht_cap.vht_supported = 1;
- vht_cap.cap = ar->vht_cap_info;
-
- if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
- val = ath10k_mac_get_vht_cap_bf_sts(ar);
- val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
- val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
-
- vht_cap.cap |= val;
- }
-
- if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
- IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
- val = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
- val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
- val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
-
- vht_cap.cap |= val;
- }
-
- mcs_map = 0;
- for (i = 0; i < 8; i++) {
- if (i < ar->num_rf_chains)
- mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i*2);
- else
- mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2);
- }
-
- vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
- vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
-
- return vht_cap;
-}
-
-static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
-{
- int i;
- struct ieee80211_sta_ht_cap ht_cap = {0};
-
- if (!(ar->ht_cap_info & WMI_HT_CAP_ENABLED))
- return ht_cap;
-
- ht_cap.ht_supported = 1;
- ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
- ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
- ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
-
- if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
- ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
-
- if (ar->ht_cap_info & WMI_HT_CAP_HT40_SGI)
- ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
-
- if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) {
- u32 smps;
-
- smps = WLAN_HT_CAP_SM_PS_DYNAMIC;
- smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
-
- ht_cap.cap |= smps;
- }
-
- if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC)
- ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
-
- if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) {
- u32 stbc;
-
- stbc = ar->ht_cap_info;
- stbc &= WMI_HT_CAP_RX_STBC;
- stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT;
- stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT;
- stbc &= IEEE80211_HT_CAP_RX_STBC;
-
- ht_cap.cap |= stbc;
- }
-
- if (ar->ht_cap_info & WMI_HT_CAP_LDPC)
- ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
-
- if (ar->ht_cap_info & WMI_HT_CAP_L_SIG_TXOP_PROT)
- ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
-
- /* max AMSDU is implicitly taken from vht_cap_info */
- if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK)
- ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
-
- for (i = 0; i < ar->num_rf_chains; i++)
- ht_cap.mcs.rx_mask[i] = 0xFF;
-
- ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-
- return ht_cap;
-}
-
static void ath10k_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -7095,8 +7128,6 @@ int ath10k_mac_register(struct ath10k *ar)
WLAN_CIPHER_SUITE_AES_CMAC,
};
struct ieee80211_supported_band *band;
- struct ieee80211_sta_vht_cap vht_cap;
- struct ieee80211_sta_ht_cap ht_cap;
void *channels;
int ret;
@@ -7104,9 +7135,6 @@ int ath10k_mac_register(struct ath10k *ar)
SET_IEEE80211_DEV(ar->hw, ar->dev);
- ht_cap = ath10k_get_ht_cap(ar);
- vht_cap = ath10k_create_vht_cap(ar);
-
BUILD_BUG_ON((ARRAY_SIZE(ath10k_2ghz_channels) +
ARRAY_SIZE(ath10k_5ghz_channels)) !=
ATH10K_NUM_CHANS);
@@ -7125,10 +7153,6 @@ int ath10k_mac_register(struct ath10k *ar)
band->channels = channels;
band->n_bitrates = ath10k_g_rates_size;
band->bitrates = ath10k_g_rates;
- band->ht_cap = ht_cap;
-
- /* Enable the VHT support at 2.4 GHz */
- band->vht_cap = vht_cap;
ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
}
@@ -7147,18 +7171,18 @@ int ath10k_mac_register(struct ath10k *ar)
band->channels = channels;
band->n_bitrates = ath10k_a_rates_size;
band->bitrates = ath10k_a_rates;
- band->ht_cap = ht_cap;
- band->vht_cap = vht_cap;
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band;
}
+ ath10k_mac_setup_ht_vht_cap(ar);
+
ar->hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
- ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
- ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
+ ar->hw->wiphy->available_antennas_rx = ar->cfg_rx_chainmask;
+ ar->hw->wiphy->available_antennas_tx = ar->cfg_tx_chainmask;
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
ar->hw->wiphy->interface_modes |=
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 5c05b0cf54a1..3fca200b986c 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -61,12 +61,14 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
#define QCA6164_2_1_DEVICE_ID (0x0041)
#define QCA6174_2_1_DEVICE_ID (0x003e)
#define QCA99X0_2_0_DEVICE_ID (0x0040)
+#define QCA9377_1_0_DEVICE_ID (0x0042)
static const struct pci_device_id ath10k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
{ PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
{ PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */
+ { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */
{0}
};
@@ -90,6 +92,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
{ QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },
+ { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
};
static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
@@ -827,6 +830,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
switch (ar->hw_rev) {
case ATH10K_HW_QCA988X:
case ATH10K_HW_QCA6174:
+ case ATH10K_HW_QCA9377:
val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CORE_CTRL_ADDRESS) &
0x7ff) << 21;
@@ -910,9 +914,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
goto done;
i = 0;
- while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id) != 0) {
+ while (ath10k_ce_completed_send_next_nolock(ce_diag,
+ NULL) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
ret = -EBUSY;
@@ -920,16 +923,6 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
}
}
- if (nbytes != completed_nbytes) {
- ret = -EIO;
- goto done;
- }
-
- if (buf != (u32)address) {
- ret = -EIO;
- goto done;
- }
-
i = 0;
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
@@ -1083,9 +1076,8 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
goto done;
i = 0;
- while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
- &completed_nbytes,
- &id) != 0) {
+ while (ath10k_ce_completed_send_next_nolock(ce_diag,
+ NULL) != 0) {
mdelay(1);
if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@@ -1094,16 +1086,6 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
}
}
- if (nbytes != completed_nbytes) {
- ret = -EIO;
- goto done;
- }
-
- if (buf != ce_data) {
- ret = -EIO;
- goto done;
- }
-
i = 0;
while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
&completed_nbytes,
@@ -1159,13 +1141,9 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state)
struct ath10k *ar = ce_state->ar;
struct sk_buff_head list;
struct sk_buff *skb;
- u32 ce_data;
- unsigned int nbytes;
- unsigned int transfer_id;
__skb_queue_head_init(&list);
- while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
- &nbytes, &transfer_id) == 0) {
+ while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
/* no need to call tx completion for NULL pointers */
if (skb == NULL)
continue;
@@ -1235,12 +1213,8 @@ static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
{
struct ath10k *ar = ce_state->ar;
struct sk_buff *skb;
- u32 ce_data;
- unsigned int nbytes;
- unsigned int transfer_id;
- while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
- &nbytes, &transfer_id) == 0) {
+ while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {
/* no need to call tx completion for NULL pointers */
if (!skb)
continue;
@@ -1513,6 +1487,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
switch (ar->hw_rev) {
case ATH10K_HW_QCA988X:
case ATH10K_HW_QCA6174:
+ case ATH10K_HW_QCA9377:
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CORE_CTRL_ADDRESS);
val &= ~CORE_CTRL_PCIE_REG_31_MASK;
@@ -1534,6 +1509,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
switch (ar->hw_rev) {
case ATH10K_HW_QCA988X:
case ATH10K_HW_QCA6174:
+ case ATH10K_HW_QCA9377:
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
CORE_CTRL_ADDRESS);
val |= CORE_CTRL_PCIE_REG_31_MASK;
@@ -1624,7 +1600,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
struct ath10k_pci *ar_pci;
struct ath10k_ce_pipe *ce_pipe;
struct ath10k_ce_ring *ce_ring;
- struct ce_desc *ce_desc;
struct sk_buff *skb;
int i;
@@ -1639,10 +1614,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
if (!pci_pipe->buf_sz)
return;
- ce_desc = ce_ring->shadow_base;
- if (WARN_ON(!ce_desc))
- return;
-
for (i = 0; i < ce_ring->nentries; i++) {
skb = ce_ring->per_transfer_context[i];
if (!skb)
@@ -1816,12 +1787,8 @@ err_dma:
static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
{
struct bmi_xfer *xfer;
- u32 ce_data;
- unsigned int nbytes;
- unsigned int transfer_id;
- if (ath10k_ce_completed_send_next(ce_state, (void **)&xfer, &ce_data,
- &nbytes, &transfer_id))
+ if (ath10k_ce_completed_send_next(ce_state, (void **)&xfer))
return;
xfer->tx_done = true;
@@ -1911,6 +1878,8 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
return 9;
}
break;
+ case QCA9377_1_0_DEVICE_ID:
+ return 2;
}
ath10k_warn(ar, "unknown number of banks, assuming 1\n");
@@ -2371,6 +2340,8 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
return ath10k_pci_qca988x_chip_reset(ar);
else if (QCA_REV_6174(ar))
return ath10k_pci_qca6174_chip_reset(ar);
+ else if (QCA_REV_9377(ar))
+ return ath10k_pci_qca6174_chip_reset(ar);
else if (QCA_REV_99X0(ar))
return ath10k_pci_qca99x0_chip_reset(ar);
else
@@ -3003,6 +2974,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
hw_rev = ATH10K_HW_QCA99X0;
pci_ps = false;
break;
+ case QCA9377_1_0_DEVICE_ID:
+ hw_rev = ATH10K_HW_QCA9377;
+ pci_ps = true;
+ break;
default:
WARN_ON(1);
return -ENOTSUPP;
@@ -3204,3 +3179,7 @@ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
+
+/* QCA9377 1.0 firmware files */
+MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
index 768bef629099..05a421bc322a 100644
--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
+++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
@@ -450,6 +450,9 @@ Fw Mode/SubMode Mask
#define QCA6174_BOARD_DATA_SZ 8192
#define QCA6174_BOARD_EXT_DATA_SZ 0
+#define QCA9377_BOARD_DATA_SZ QCA6174_BOARD_DATA_SZ
+#define QCA9377_BOARD_EXT_DATA_SZ 0
+
#define QCA99X0_BOARD_DATA_SZ 12288
#define QCA99X0_BOARD_EXT_DATA_SZ 0
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
index b084f88da102..1d5a2fdcbf56 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -139,11 +139,181 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
return cfg80211_testmode_reply(skb);
}
-static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
+static int ath10k_tm_fetch_utf_firmware_api_2(struct ath10k *ar)
+{
+ size_t len, magic_len, ie_len;
+ struct ath10k_fw_ie *hdr;
+ char filename[100];
+ __le32 *version;
+ const u8 *data;
+ int ie_id, ret;
+
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ar->hw_params.fw.dir, ATH10K_FW_UTF_API2_FILE);
+
+ /* load utf firmware image */
+ ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
+ if (ret) {
+ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
+ filename, ret);
+ return ret;
+ }
+
+ data = ar->testmode.utf->data;
+ len = ar->testmode.utf->size;
+
+ /* FIXME: call release_firmware() in error cases */
+
+ /* magic also includes the null byte, check that as well */
+ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
+
+ if (len < magic_len) {
+ ath10k_err(ar, "utf firmware file is too small to contain magic\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
+ ath10k_err(ar, "invalid firmware magic\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* jump over the padding */
+ magic_len = ALIGN(magic_len, 4);
+
+ len -= magic_len;
+ data += magic_len;
+
+ /* loop elements */
+ while (len > sizeof(struct ath10k_fw_ie)) {
+ hdr = (struct ath10k_fw_ie *)data;
+
+ ie_id = le32_to_cpu(hdr->id);
+ ie_len = le32_to_cpu(hdr->len);
+
+ len -= sizeof(*hdr);
+ data += sizeof(*hdr);
+
+ if (len < ie_len) {
+ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
+ ie_id, len, ie_len);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ switch (ie_id) {
+ case ATH10K_FW_IE_FW_VERSION:
+ if (ie_len > sizeof(ar->testmode.utf_version) - 1)
+ break;
+
+ memcpy(ar->testmode.utf_version, data, ie_len);
+ ar->testmode.utf_version[ie_len] = '\0';
+
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
+ "testmode found fw utf version %s\n",
+ ar->testmode.utf_version);
+ break;
+ case ATH10K_FW_IE_TIMESTAMP:
+ /* ignore timestamp, but don't warn about it either */
+ break;
+ case ATH10K_FW_IE_FW_IMAGE:
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
+ "testmode found fw image ie (%zd B)\n",
+ ie_len);
+
+ ar->testmode.utf_firmware_data = data;
+ ar->testmode.utf_firmware_len = ie_len;
+ break;
+ case ATH10K_FW_IE_WMI_OP_VERSION:
+ if (ie_len != sizeof(u32))
+ break;
+ version = (__le32 *)data;
+ ar->testmode.op_version = le32_to_cpup(version);
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode found fw ie wmi op version %d\n",
+ ar->testmode.op_version);
+ break;
+ default:
+ ath10k_warn(ar, "Unknown testmode FW IE: %u\n",
+ le32_to_cpu(hdr->id));
+ break;
+ }
+ /* jump over the padding */
+ ie_len = ALIGN(ie_len, 4);
+
+ len -= ie_len;
+ data += ie_len;
+ }
+
+ if (!ar->testmode.utf_firmware_data || !ar->testmode.utf_firmware_len) {
+ ath10k_err(ar, "No ATH10K_FW_IE_FW_IMAGE found\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ release_firmware(ar->testmode.utf);
+
+ return ret;
+}
+
+static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
{
char filename[100];
int ret;
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
+
+ /* load utf firmware image */
+ ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
+ if (ret) {
+ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
+ filename, ret);
+ return ret;
+ }
+
+ /* We didn't find FW UTF API 1 ("utf.bin") does not advertise
+ * firmware features. Do an ugly hack where we force the firmware
+ * features to match with 10.1 branch so that wmi.c will use the
+ * correct WMI interface.
+ */
+
+ ar->testmode.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
+ ar->testmode.utf_firmware_data = ar->testmode.utf->data;
+ ar->testmode.utf_firmware_len = ar->testmode.utf->size;
+
+ return 0;
+}
+
+static int ath10k_tm_fetch_firmware(struct ath10k *ar)
+{
+ int ret;
+
+ ret = ath10k_tm_fetch_utf_firmware_api_2(ar);
+ if (ret == 0) {
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
+ return 0;
+ }
+
+ ret = ath10k_tm_fetch_utf_firmware_api_1(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
+
+ return 0;
+}
+
+static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
+{
+ const char *ver;
+ int ret;
+
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
mutex_lock(&ar->conf_mutex);
@@ -165,36 +335,27 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
goto err;
}
- snprintf(filename, sizeof(filename), "%s/%s",
- ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
-
- /* load utf firmware image */
- ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
+ ret = ath10k_tm_fetch_firmware(ar);
if (ret) {
- ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
- filename, ret);
+ ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
goto err;
}
spin_lock_bh(&ar->data_lock);
-
ar->testmode.utf_monitor = true;
-
spin_unlock_bh(&ar->data_lock);
-
BUILD_BUG_ON(sizeof(ar->fw_features) !=
sizeof(ar->testmode.orig_fw_features));
memcpy(ar->testmode.orig_fw_features, ar->fw_features,
sizeof(ar->fw_features));
ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
-
- /* utf.bin firmware image does not advertise firmware features. Do
- * an ugly hack where we force the firmware features so that wmi.c
- * will use the correct WMI interface.
- */
memset(ar->fw_features, 0, sizeof(ar->fw_features));
- ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
+
+ ar->wmi.op_version = ar->testmode.op_version;
+
+ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
+ ar->wmi.op_version);
ret = ath10k_hif_power_up(ar);
if (ret) {
@@ -212,7 +373,12 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
ar->state = ATH10K_STATE_UTF;
- ath10k_info(ar, "UTF firmware started\n");
+ if (strlen(ar->testmode.utf_version) > 0)
+ ver = ar->testmode.utf_version;
+ else
+ ver = "API 1";
+
+ ath10k_info(ar, "UTF firmware %s started\n", ver);
mutex_unlock(&ar->conf_mutex);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index b54aa08cb25c..8f4f6a892581 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -182,6 +182,10 @@ struct wmi_ops {
void (*fw_stats_fill)(struct ath10k *ar,
struct ath10k_fw_stats *fw_stats,
char *buf);
+ struct sk_buff *(*gen_pdev_enable_adaptive_cca)(struct ath10k *ar,
+ u8 enable,
+ u32 detect_level,
+ u32 detect_margin);
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1302,4 +1306,25 @@ ath10k_wmi_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats,
ar->wmi.ops->fw_stats_fill(ar, fw_stats, buf);
return 0;
}
+
+static inline int
+ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
+ u32 detect_level, u32 detect_margin)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_enable_adaptive_cca)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_enable_adaptive_cca(ar, enable,
+ detect_level,
+ detect_margin);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid);
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 8f835480a62c..6fbd17b69469 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -23,6 +23,7 @@
#include "wmi-ops.h"
#include "wmi-tlv.h"
#include "p2p.h"
+#include "testmode.h"
/***************/
/* TLV helpers */
@@ -419,6 +420,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_tlv_event_id id;
+ bool consumed;
cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -428,6 +430,18 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
+ consumed = ath10k_tm_event_wmi(ar, id, skb);
+
+ /* Ready event must be handled normally also in UTF mode so that we
+ * know the UTF firmware has booted, others we are just bypass WMI
+ * events to testmode.
+ */
+ if (consumed && id != WMI_TLV_READY_EVENTID) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv testmode consumed 0x%x\n", id);
+ goto out;
+ }
+
switch (id) {
case WMI_TLV_MGMT_RX_EVENTID:
ath10k_wmi_event_mgmt_rx(ar, skb);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 6e7d7a7f6a97..7569db0f69b5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -148,6 +148,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
.gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_enable_adaptive_cca_cmdid = WMI_CMD_UNSUPPORTED,
.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED,
@@ -313,6 +314,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_enable_adaptive_cca_cmdid = WMI_CMD_UNSUPPORTED,
.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED,
@@ -477,6 +479,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
+ .pdev_enable_adaptive_cca_cmdid = WMI_10_2_SET_CCA_PARAMS,
.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED,
@@ -1407,6 +1410,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_enable_adaptive_cca_cmdid = WMI_CMD_UNSUPPORTED,
.scan_update_request_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED,
.vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED,
@@ -2475,6 +2479,47 @@ void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
dst->txop_ovf = __le32_to_cpu(src->txop_ovf);
}
+static void
+ath10k_wmi_10_4_pull_pdev_stats_tx(const struct wmi_10_4_pdev_stats_tx *src,
+ struct ath10k_fw_stats_pdev *dst)
+{
+ dst->comp_queued = __le32_to_cpu(src->comp_queued);
+ dst->comp_delivered = __le32_to_cpu(src->comp_delivered);
+ dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued);
+ dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued);
+ dst->wmm_drop = __le32_to_cpu(src->wmm_drop);
+ dst->local_enqued = __le32_to_cpu(src->local_enqued);
+ dst->local_freed = __le32_to_cpu(src->local_freed);
+ dst->hw_queued = __le32_to_cpu(src->hw_queued);
+ dst->hw_reaped = __le32_to_cpu(src->hw_reaped);
+ dst->underrun = __le32_to_cpu(src->underrun);
+ dst->tx_abort = __le32_to_cpu(src->tx_abort);
+ dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed);
+ dst->tx_ko = __le32_to_cpu(src->tx_ko);
+ dst->data_rc = __le32_to_cpu(src->data_rc);
+ dst->self_triggers = __le32_to_cpu(src->self_triggers);
+ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure);
+ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err);
+ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry);
+ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout);
+ dst->pdev_resets = __le32_to_cpu(src->pdev_resets);
+ dst->phy_underrun = __le32_to_cpu(src->phy_underrun);
+ dst->txop_ovf = __le32_to_cpu(src->txop_ovf);
+ dst->hw_paused = __le32_to_cpu(src->hw_paused);
+ dst->seq_posted = __le32_to_cpu(src->seq_posted);
+ dst->seq_failed_queueing =
+ __le32_to_cpu(src->seq_failed_queueing);
+ dst->seq_completed = __le32_to_cpu(src->seq_completed);
+ dst->seq_restarted = __le32_to_cpu(src->seq_restarted);
+ dst->mu_seq_posted = __le32_to_cpu(src->mu_seq_posted);
+ dst->mpdus_sw_flush = __le32_to_cpu(src->mpdus_sw_flush);
+ dst->mpdus_hw_filter = __le32_to_cpu(src->mpdus_hw_filter);
+ dst->mpdus_truncated = __le32_to_cpu(src->mpdus_truncated);
+ dst->mpdus_ack_failed = __le32_to_cpu(src->mpdus_ack_failed);
+ dst->mpdus_hw_filter = __le32_to_cpu(src->mpdus_hw_filter);
+ dst->mpdus_expired = __le32_to_cpu(src->mpdus_expired);
+}
+
void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
struct ath10k_fw_stats_pdev *dst)
{
@@ -2785,6 +2830,86 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ const struct wmi_10_2_stats_event *ev = (void *)skb->data;
+ u32 num_pdev_stats;
+ u32 num_pdev_ext_stats;
+ u32 num_vdev_stats;
+ u32 num_peer_stats;
+ int i;
+
+ if (!skb_pull(skb, sizeof(*ev)))
+ return -EPROTO;
+
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ for (i = 0; i < num_pdev_stats; i++) {
+ const struct wmi_10_4_pdev_stats *src;
+ struct ath10k_fw_stats_pdev *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath10k_wmi_10_4_pull_pdev_stats_tx(&src->tx, dst);
+ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+ dst->rx_ovfl_errs = __le32_to_cpu(src->rx_ovfl_errs);
+ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
+
+ list_add_tail(&dst->list, &stats->pdevs);
+ }
+
+ for (i = 0; i < num_pdev_ext_stats; i++) {
+ const struct wmi_10_2_pdev_ext_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.
+ */
+ }
+
+ /* fw doesn't implement vdev stats */
+
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_10_4_peer_stats *src;
+ struct ath10k_fw_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->peer_rssi = __le32_to_cpu(src->peer_rssi);
+ dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
+ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
+ /* FIXME: expose 10.4 specific values */
+
+ list_add_tail(&dst->list, &stats->peers);
+ }
+
+ return 0;
+}
+
void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
@@ -4335,8 +4460,10 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
ar->num_rf_chains = ar->max_spatial_stream;
}
- ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
- ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
+ if (!ar->cfg_tx_chainmask) {
+ ar->cfg_tx_chainmask = (1 << ar->num_rf_chains) - 1;
+ ar->cfg_rx_chainmask = (1 << ar->num_rf_chains) - 1;
+ }
if (strlen(ar->hw->wiphy->fw_version) == 0) {
snprintf(ar->hw->wiphy->fw_version,
@@ -4931,6 +5058,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_WMI,
"received event id %d not implemented\n", id);
break;
+ case WMI_10_4_UPDATE_STATS_EVENTID:
+ ath10k_wmi_event_update_stats(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -6996,6 +7126,112 @@ unlock:
buf[len] = 0;
}
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
+ u32 detect_level, u32 detect_margin)
+{
+ struct wmi_pdev_set_adaptive_cca_params *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_pdev_set_adaptive_cca_params *)skb->data;
+ cmd->enable = __cpu_to_le32(enable);
+ cmd->cca_detect_level = __cpu_to_le32(detect_level);
+ cmd->cca_detect_margin = __cpu_to_le32(detect_margin);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi pdev set adaptive cca params enable:%d detection level:%d detection margin:%d\n",
+ enable, detect_level, detect_margin);
+ return skb;
+}
+
+void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
+ struct ath10k_fw_stats *fw_stats,
+ char *buf)
+{
+ u32 len = 0;
+ u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
+ const struct ath10k_fw_stats_pdev *pdev;
+ const struct ath10k_fw_stats_vdev *vdev;
+ const struct ath10k_fw_stats_peer *peer;
+ size_t num_peers;
+ size_t num_vdevs;
+
+ spin_lock_bh(&ar->data_lock);
+
+ pdev = list_first_entry_or_null(&fw_stats->pdevs,
+ struct ath10k_fw_stats_pdev, list);
+ if (!pdev) {
+ ath10k_warn(ar, "failed to get pdev stats\n");
+ goto unlock;
+ }
+
+ num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers);
+ num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs);
+
+ ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len);
+ ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len);
+ ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len);
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "HW paused", pdev->hw_paused);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Seqs posted", pdev->seq_posted);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Seqs failed queueing", pdev->seq_failed_queueing);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Seqs completed", pdev->seq_completed);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Seqs restarted", pdev->seq_restarted);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MU Seqs posted", pdev->mu_seq_posted);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs SW flushed", pdev->mpdus_sw_flush);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs HW filtered", pdev->mpdus_hw_filter);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs truncated", pdev->mpdus_truncated);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs receive no ACK", pdev->mpdus_ack_failed);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "MPDUs expired", pdev->mpdus_expired);
+
+ ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len);
+ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+ "Num Rx Overflow errors", pdev->rx_ovfl_errs);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+ "ath10k VDEV stats", num_vdevs);
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "=================");
+
+ list_for_each_entry(vdev, &fw_stats->vdevs, list) {
+ ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len);
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+ "ath10k PEER stats", num_peers);
+ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+ "=================");
+
+ list_for_each_entry(peer, &fw_stats->peers, list) {
+ ath10k_wmi_fw_peer_stats_fill(peer, buf, &len);
+ }
+
+unlock:
+ spin_unlock_bh(&ar->data_lock);
+
+ if (len >= buf_len)
+ buf[len - 1] = 0;
+ else
+ buf[len] = 0;
+}
+
static const struct wmi_ops wmi_ops = {
.rx = ath10k_wmi_op_rx,
.map_svc = wmi_main_svc_map,
@@ -7059,6 +7295,7 @@ static const struct wmi_ops wmi_ops = {
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
/* .gen_adaptive_qcs not implemented */
+ /* .gen_pdev_enable_adaptive_cca not implemented */
};
static const struct wmi_ops wmi_10_1_ops = {
@@ -7125,6 +7362,7 @@ static const struct wmi_ops wmi_10_1_ops = {
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
/* .gen_adaptive_qcs not implemented */
+ /* .gen_pdev_enable_adaptive_cca not implemented */
};
static const struct wmi_ops wmi_10_2_ops = {
@@ -7188,6 +7426,7 @@ static const struct wmi_ops wmi_10_2_ops = {
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
+ /* .gen_pdev_enable_adaptive_cca not implemented */
};
static const struct wmi_ops wmi_10_2_4_ops = {
@@ -7251,6 +7490,8 @@ static const struct wmi_ops wmi_10_2_4_ops = {
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
+ .gen_pdev_enable_adaptive_cca =
+ ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
@@ -7261,6 +7502,7 @@ static const struct wmi_ops wmi_10_4_ops = {
.rx = ath10k_wmi_10_4_op_rx,
.map_svc = wmi_10_4_svc_map,
+ .pull_fw_stats = ath10k_wmi_10_4_op_pull_fw_stats,
.pull_scan = ath10k_wmi_op_pull_scan_ev,
.pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev,
.pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev,
@@ -7310,9 +7552,11 @@ static const struct wmi_ops wmi_10_4_ops = {
.gen_addba_send = ath10k_wmi_op_gen_addba_send,
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
+ .fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill,
/* shared with 10.2 */
.gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
+ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
};
int ath10k_wmi_attach(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 6e84d1c1a6ca..72a4ef709577 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -772,6 +772,7 @@ struct wmi_cmd_map {
u32 mu_cal_start_cmdid;
u32 set_cca_params_cmdid;
u32 pdev_bss_chan_info_request_cmdid;
+ u32 pdev_enable_adaptive_cca_cmdid;
};
/*
@@ -1381,6 +1382,9 @@ enum wmi_10_2_cmd_id {
WMI_10_2_VDEV_ATF_REQUEST_CMDID,
WMI_10_2_PEER_ATF_REQUEST_CMDID,
WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
+ WMI_10_2_MU_CAL_START_CMDID,
+ WMI_10_2_SET_LTEU_CONFIG_CMDID,
+ WMI_10_2_SET_CCA_PARAMS,
WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
};
@@ -3862,6 +3866,111 @@ struct wmi_pdev_stats_tx {
__le32 txop_ovf;
} __packed;
+struct wmi_10_4_pdev_stats_tx {
+ /* Num HTT cookies queued to dispatch list */
+ __le32 comp_queued;
+
+ /* Num HTT cookies dispatched */
+ __le32 comp_delivered;
+
+ /* Num MSDU queued to WAL */
+ __le32 msdu_enqued;
+
+ /* Num MPDU queue to WAL */
+ __le32 mpdu_enqued;
+
+ /* Num MSDUs dropped by WMM limit */
+ __le32 wmm_drop;
+
+ /* Num Local frames queued */
+ __le32 local_enqued;
+
+ /* Num Local frames done */
+ __le32 local_freed;
+
+ /* Num queued to HW */
+ __le32 hw_queued;
+
+ /* Num PPDU reaped from HW */
+ __le32 hw_reaped;
+
+ /* Num underruns */
+ __le32 underrun;
+
+ /* HW Paused. */
+ __le32 hw_paused;
+
+ /* Num PPDUs cleaned up in TX abort */
+ __le32 tx_abort;
+
+ /* Num MPDUs requed by SW */
+ __le32 mpdus_requed;
+
+ /* excessive retries */
+ __le32 tx_ko;
+
+ /* data hw rate code */
+ __le32 data_rc;
+
+ /* Scheduler self triggers */
+ __le32 self_triggers;
+
+ /* frames dropped due to excessive sw retries */
+ __le32 sw_retry_failure;
+
+ /* illegal rate phy errors */
+ __le32 illgl_rate_phy_err;
+
+ /* wal pdev continuous xretry */
+ __le32 pdev_cont_xretry;
+
+ /* wal pdev tx timeouts */
+ __le32 pdev_tx_timeout;
+
+ /* wal pdev resets */
+ __le32 pdev_resets;
+
+ /* frames dropped due to non-availability of stateless TIDs */
+ __le32 stateless_tid_alloc_failure;
+
+ __le32 phy_underrun;
+
+ /* MPDU is more than txop limit */
+ __le32 txop_ovf;
+
+ /* Number of Sequences posted */
+ __le32 seq_posted;
+
+ /* Number of Sequences failed queueing */
+ __le32 seq_failed_queueing;
+
+ /* Number of Sequences completed */
+ __le32 seq_completed;
+
+ /* Number of Sequences restarted */
+ __le32 seq_restarted;
+
+ /* Number of MU Sequences posted */
+ __le32 mu_seq_posted;
+
+ /* Num MPDUs flushed by SW, HWPAUSED,SW TXABORT(Reset,channel change) */
+ __le32 mpdus_sw_flush;
+
+ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */
+ __le32 mpdus_hw_filter;
+
+ /* Num MPDUs truncated by PDG
+ * (TXOP, TBTT, PPDU_duration based on rate, dyn_bw)
+ */
+ __le32 mpdus_truncated;
+
+ /* Num MPDUs that was tried but didn't receive ACK or BA */
+ __le32 mpdus_ack_failed;
+
+ /* Num MPDUs that was dropped due to expiry. */
+ __le32 mpdus_expired;
+} __packed;
+
struct wmi_pdev_stats_rx {
/* Cnts any change in ring routing mid-ppdu */
__le32 mid_ppdu_route_change;
@@ -4035,6 +4144,16 @@ struct wmi_10_2_pdev_stats {
struct wmi_pdev_stats_extra extra;
} __packed;
+struct wmi_10_4_pdev_stats {
+ struct wmi_pdev_stats_base base;
+ struct wmi_10_4_pdev_stats_tx tx;
+ struct wmi_pdev_stats_rx rx;
+ __le32 rx_ovfl_errs;
+ struct wmi_pdev_stats_mem mem;
+ __le32 sram_free_size;
+ struct wmi_pdev_stats_extra extra;
+} __packed;
+
/*
* VDEV statistics
* TODO: add all VDEV stats here
@@ -4076,6 +4195,23 @@ struct wmi_10_2_4_peer_stats {
__le32 unknown_value; /* FIXME: what is this word? */
} __packed;
+struct wmi_10_4_peer_stats {
+ struct wmi_mac_addr peer_macaddr;
+ __le32 peer_rssi;
+ __le32 peer_rssi_seq_num;
+ __le32 peer_tx_rate;
+ __le32 peer_rx_rate;
+ __le32 current_per;
+ __le32 retries;
+ __le32 tx_rate_count;
+ __le32 max_4ms_frame_len;
+ __le32 total_sub_frames;
+ __le32 tx_bytes;
+ __le32 num_pkt_loss_overflow[4];
+ __le32 num_pkt_loss_excess_retry[4];
+ __le32 peer_rssi_changed;
+} __packed;
+
struct wmi_10_2_pdev_ext_stats {
__le32 rx_rssi_comb;
__le32 rx_rssi[4];
@@ -6094,6 +6230,15 @@ enum wmi_txbf_conf {
WMI_TXBF_CONF_AFTER_ASSOC,
};
+#define WMI_CCA_DETECT_LEVEL_AUTO 0
+#define WMI_CCA_DETECT_MARGIN_AUTO 0
+
+struct wmi_pdev_set_adaptive_cca_params {
+ __le32 enable;
+ __le32 cca_detect_level;
+ __le32 cca_detect_margin;
+} __packed;
+
struct ath10k;
struct ath10k_vif;
struct ath10k_fw_stats_pdev;
@@ -6188,5 +6333,8 @@ void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar,
char *buf);
size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head);
size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head);
+void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
+ struct ath10k_fw_stats *fw_stats,
+ char *buf);
#endif /* _WMI_H_ */
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 76b682e566ab..81ac8c59f0ec 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3231,6 +3231,15 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
wait, buf, len, no_cck);
}
+static int ath6kl_get_antenna(struct wiphy *wiphy,
+ u32 *tx_ant, u32 *rx_ant)
+{
+ struct ath6kl *ar = wiphy_priv(wiphy);
+ *tx_ant = ar->hw.tx_ant;
+ *rx_ant = ar->hw.rx_ant;
+ return 0;
+}
+
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
struct wireless_dev *wdev,
u16 frame_type, bool reg)
@@ -3447,6 +3456,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
.mgmt_tx = ath6kl_mgmt_tx,
.mgmt_frame_register = ath6kl_mgmt_frame_register,
+ .get_antenna = ath6kl_get_antenna,
.sched_scan_start = ath6kl_cfg80211_sscan_start,
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
.set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
@@ -3634,6 +3644,127 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
ar->num_vif--;
}
+static const char ath6kl_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
+ /* Common stats names used by many drivers. */
+ "tx_pkts_nic", "tx_bytes_nic", "rx_pkts_nic", "rx_bytes_nic",
+
+ /* TX stats. */
+ "d_tx_ucast_pkts", "d_tx_bcast_pkts",
+ "d_tx_ucast_bytes", "d_tx_bcast_bytes",
+ "d_tx_rts_ok", "d_tx_error", "d_tx_fail",
+ "d_tx_retry", "d_tx_multi_retry", "d_tx_rts_fail",
+ "d_tx_tkip_counter_measures",
+
+ /* RX Stats. */
+ "d_rx_ucast_pkts", "d_rx_ucast_rate", "d_rx_bcast_pkts",
+ "d_rx_ucast_bytes", "d_rx_bcast_bytes", "d_rx_frag_pkt",
+ "d_rx_error", "d_rx_crc_err", "d_rx_keycache_miss",
+ "d_rx_decrypt_crc_err", "d_rx_duplicate_frames",
+ "d_rx_mic_err", "d_rx_tkip_format_err", "d_rx_ccmp_format_err",
+ "d_rx_ccmp_replay_err",
+
+ /* Misc stats. */
+ "d_beacon_miss", "d_num_connects", "d_num_disconnects",
+ "d_beacon_avg_rssi", "d_arp_received", "d_arp_matched",
+ "d_arp_replied"
+};
+
+#define ATH6KL_STATS_LEN ARRAY_SIZE(ath6kl_gstrings_sta_stats)
+
+static int ath6kl_get_sset_count(struct net_device *dev, int sset)
+{
+ int rv = 0;
+
+ if (sset == ETH_SS_STATS)
+ rv += ATH6KL_STATS_LEN;
+
+ if (rv == 0)
+ return -EOPNOTSUPP;
+ return rv;
+}
+
+static void ath6kl_get_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct ath6kl_vif *vif = netdev_priv(dev);
+ struct ath6kl *ar = vif->ar;
+ int i = 0;
+ struct target_stats *tgt_stats;
+
+ memset(data, 0, sizeof(u64) * ATH6KL_STATS_LEN);
+
+ ath6kl_read_tgt_stats(ar, vif);
+
+ tgt_stats = &vif->target_stats;
+
+ data[i++] = tgt_stats->tx_ucast_pkt + tgt_stats->tx_bcast_pkt;
+ data[i++] = tgt_stats->tx_ucast_byte + tgt_stats->tx_bcast_byte;
+ data[i++] = tgt_stats->rx_ucast_pkt + tgt_stats->rx_bcast_pkt;
+ data[i++] = tgt_stats->rx_ucast_byte + tgt_stats->rx_bcast_byte;
+
+ data[i++] = tgt_stats->tx_ucast_pkt;
+ data[i++] = tgt_stats->tx_bcast_pkt;
+ data[i++] = tgt_stats->tx_ucast_byte;
+ data[i++] = tgt_stats->tx_bcast_byte;
+ data[i++] = tgt_stats->tx_rts_success_cnt;
+ data[i++] = tgt_stats->tx_err;
+ data[i++] = tgt_stats->tx_fail_cnt;
+ data[i++] = tgt_stats->tx_retry_cnt;
+ data[i++] = tgt_stats->tx_mult_retry_cnt;
+ data[i++] = tgt_stats->tx_rts_fail_cnt;
+ data[i++] = tgt_stats->tkip_cnter_measures_invoked;
+
+ data[i++] = tgt_stats->rx_ucast_pkt;
+ data[i++] = tgt_stats->rx_ucast_rate;
+ data[i++] = tgt_stats->rx_bcast_pkt;
+ data[i++] = tgt_stats->rx_ucast_byte;
+ data[i++] = tgt_stats->rx_bcast_byte;
+ data[i++] = tgt_stats->rx_frgment_pkt;
+ data[i++] = tgt_stats->rx_err;
+ data[i++] = tgt_stats->rx_crc_err;
+ data[i++] = tgt_stats->rx_key_cache_miss;
+ data[i++] = tgt_stats->rx_decrypt_err;
+ data[i++] = tgt_stats->rx_dupl_frame;
+ data[i++] = tgt_stats->tkip_local_mic_fail;
+ data[i++] = tgt_stats->tkip_fmt_err;
+ data[i++] = tgt_stats->ccmp_fmt_err;
+ data[i++] = tgt_stats->ccmp_replays;
+
+ data[i++] = tgt_stats->cs_bmiss_cnt;
+ data[i++] = tgt_stats->cs_connect_cnt;
+ data[i++] = tgt_stats->cs_discon_cnt;
+ data[i++] = tgt_stats->cs_ave_beacon_rssi;
+ data[i++] = tgt_stats->arp_received;
+ data[i++] = tgt_stats->arp_matched;
+ data[i++] = tgt_stats->arp_replied;
+
+ if (i != ATH6KL_STATS_LEN) {
+ WARN_ON_ONCE(1);
+ ath6kl_err("ethtool stats error, i: %d STATS_LEN: %d\n",
+ i, (int)ATH6KL_STATS_LEN);
+ }
+}
+
+/* These stats are per NIC, not really per vdev, so we just ignore dev. */
+static void ath6kl_get_strings(struct net_device *dev, u32 sset, u8 *data)
+{
+ int sz_sta_stats = 0;
+
+ if (sset == ETH_SS_STATS) {
+ sz_sta_stats = sizeof(ath6kl_gstrings_sta_stats);
+ memcpy(data, ath6kl_gstrings_sta_stats, sz_sta_stats);
+ }
+}
+
+static const struct ethtool_ops ath6kl_ethtool_ops = {
+ .get_drvinfo = cfg80211_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_strings = ath6kl_get_strings,
+ .get_ethtool_stats = ath6kl_get_stats,
+ .get_sset_count = ath6kl_get_sset_count,
+};
+
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
unsigned char name_assign_type,
enum nl80211_iftype type,
@@ -3679,6 +3810,8 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
if (ath6kl_cfg80211_vif_init(vif))
goto err;
+ netdev_set_default_ethtool_ops(ndev, &ath6kl_ethtool_ops);
+
if (register_netdevice(ndev))
goto err;
@@ -3786,6 +3919,9 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ath6kl_band_2ghz.ht_cap.ht_supported = false;
ath6kl_band_5ghz.ht_cap.cap = 0;
ath6kl_band_5ghz.ht_cap.ht_supported = false;
+
+ if (ht)
+ ath6kl_err("Firmware lacks RSN-CAP-OVERRIDE, so HT (802.11n) is disabled.");
}
if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
@@ -3794,11 +3930,18 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+ ar->hw.tx_ant = 2;
+ ar->hw.rx_ant = 2;
} else {
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+ ar->hw.tx_ant = 1;
+ ar->hw.rx_ant = 1;
}
+ wiphy->available_antennas_tx = ar->hw.tx_ant;
+ wiphy->available_antennas_rx = ar->hw.rx_ant;
+
if (band_2gig)
wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
if (band_5gig)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 2b78c863d030..5f3acfe6015e 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -782,6 +782,8 @@ struct ath6kl {
u32 refclk_hz;
u32 uarttx_pin;
u32 testscript_addr;
+ u8 tx_ant;
+ u8 rx_ant;
enum wmi_phy_cap cap;
u32 flags;
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 81ba48d2938b..e2b7809d7886 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -98,6 +98,33 @@ void ath6kl_warn(const char *fmt, ...)
}
EXPORT_SYMBOL(ath6kl_warn);
+int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif)
+{
+ long left;
+
+ if (down_interruptible(&ar->sem))
+ return -EBUSY;
+
+ set_bit(STATS_UPDATE_PEND, &vif->flags);
+
+ if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
+ up(&ar->sem);
+ return -EIO;
+ }
+
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ !test_bit(STATS_UPDATE_PEND,
+ &vif->flags), WMI_TIMEOUT);
+
+ up(&ar->sem);
+
+ if (left <= 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+EXPORT_SYMBOL(ath6kl_read_tgt_stats);
+
#ifdef CONFIG_ATH6KL_DEBUG
void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
@@ -544,42 +571,24 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
char *buf;
unsigned int len = 0, buf_len = 1500;
int i;
- long left;
ssize_t ret_cnt;
+ int rv;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
- tgt_stats = &vif->target_stats;
-
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- if (down_interruptible(&ar->sem)) {
+ rv = ath6kl_read_tgt_stats(ar, vif);
+ if (rv < 0) {
kfree(buf);
- return -EBUSY;
+ return rv;
}
- set_bit(STATS_UPDATE_PEND, &vif->flags);
-
- if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
- up(&ar->sem);
- kfree(buf);
- return -EIO;
- }
-
- left = wait_event_interruptible_timeout(ar->event_wq,
- !test_bit(STATS_UPDATE_PEND,
- &vif->flags), WMI_TIMEOUT);
-
- up(&ar->sem);
-
- if (left <= 0) {
- kfree(buf);
- return -ETIMEDOUT;
- }
+ tgt_stats = &vif->target_stats;
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%25s\n",
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index 19106ed28961..0614393dd7ae 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -59,6 +59,8 @@ enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
};
+int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif);
+
#ifdef CONFIG_ATH6KL_DEBUG
void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 6e473fa4b13c..e3f3a6ae0c0a 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -994,7 +994,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
switch (ie_id) {
case ATH6KL_FW_IE_FW_VERSION:
strlcpy(ar->wiphy->fw_version, data,
- sizeof(ar->wiphy->fw_version));
+ min(sizeof(ar->wiphy->fw_version), ie_len+1));
ath6kl_dbg(ATH6KL_DBG_BOOT,
"found fw version %s\n",
diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c
index 3b289f933405..84afcf78151f 100644
--- a/drivers/net/wireless/ath/ath9k/common-debug.c
+++ b/drivers/net/wireless/ath/ath9k/common-debug.c
@@ -207,6 +207,7 @@ static ssize_t read_file_phy_err(struct file *file, char __user *user_buf,
PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR);
PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE);
PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR);
+
PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING);
PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
@@ -214,17 +215,24 @@ static ssize_t read_file_phy_err(struct file *file, char __user *user_buf,
PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP);
PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE);
PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART);
- PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
+
+ PHY_ERR("CCK-BLOCKER ERR", ATH9K_PHYERR_CCK_BLOCKER);
PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING);
PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC);
PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
- PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
- PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP);
+ PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE);
+ PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART);
+
PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR);
PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+ PHY_ERR("HT-ZLF ERR", ATH9K_PHYERR_HT_ZLF);
+
+ PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT);
+ PHY_ERR("GREEN-FIELD ERR", ATH9K_PHYERR_GREEN_FIELD);
+ PHY_ERR("SPECTRAL ERR", ATH9K_PHYERR_SPECTRAL);
if (len > size)
len = size;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index e55fa11894b6..7fbf7f965f61 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -209,21 +209,25 @@ enum ath9k_phyerr {
ATH9K_PHYERR_OFDM_POWER_DROP = 21,
ATH9K_PHYERR_OFDM_SERVICE = 22,
ATH9K_PHYERR_OFDM_RESTART = 23,
- ATH9K_PHYERR_FALSE_RADAR_EXT = 24,
+ ATH9K_PHYERR_CCK_BLOCKER = 24,
ATH9K_PHYERR_CCK_TIMING = 25,
ATH9K_PHYERR_CCK_HEADER_CRC = 26,
ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27,
+ ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 28,
+ ATH9K_PHYERR_CCK_POWER_DROP = 29,
ATH9K_PHYERR_CCK_SERVICE = 30,
ATH9K_PHYERR_CCK_RESTART = 31,
- ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32,
- ATH9K_PHYERR_CCK_POWER_DROP = 33,
- ATH9K_PHYERR_HT_CRC_ERROR = 34,
- ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
- ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
+ ATH9K_PHYERR_HT_CRC_ERROR = 32,
+ ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 33,
+ ATH9K_PHYERR_HT_RATE_ILLEGAL = 34,
+ ATH9K_PHYERR_HT_ZLF = 35,
+
+ ATH9K_PHYERR_FALSE_RADAR_EXT = 36,
+ ATH9K_PHYERR_GREEN_FIELD = 37,
+ ATH9K_PHYERR_SPECTRAL = 38,
- ATH9K_PHYERR_SPECTRAL = 38,
ATH9K_PHYERR_MAX = 39,
};
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 086549b732b9..f8dfa05b290a 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -79,6 +79,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
struct wcn36xx_dxe_ctl *cur_ctl = NULL;
int i;
+ spin_lock_init(&ch->lock);
for (i = 0; i < ch->desc_num; i++) {
cur_ctl = kzalloc(sizeof(*cur_ctl), GFP_KERNEL);
if (!cur_ctl)
@@ -169,7 +170,7 @@ void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn)
wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_h_ch);
}
-static int wcn36xx_dxe_init_descs(struct wcn36xx_dxe_ch *wcn_ch)
+static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn_ch)
{
struct wcn36xx_dxe_desc *cur_dxe = NULL;
struct wcn36xx_dxe_desc *prev_dxe = NULL;
@@ -178,7 +179,7 @@ static int wcn36xx_dxe_init_descs(struct wcn36xx_dxe_ch *wcn_ch)
int i;
size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
- wcn_ch->cpu_addr = dma_alloc_coherent(NULL, size, &wcn_ch->dma_addr,
+ wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr,
GFP_KERNEL);
if (!wcn_ch->cpu_addr)
return -ENOMEM;
@@ -270,7 +271,7 @@ static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch)
return 0;
}
-static int wcn36xx_dxe_fill_skb(struct wcn36xx_dxe_ctl *ctl)
+static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl)
{
struct wcn36xx_dxe_desc *dxe = ctl->desc;
struct sk_buff *skb;
@@ -279,7 +280,7 @@ static int wcn36xx_dxe_fill_skb(struct wcn36xx_dxe_ctl *ctl)
if (skb == NULL)
return -ENOMEM;
- dxe->dst_addr_l = dma_map_single(NULL,
+ dxe->dst_addr_l = dma_map_single(dev,
skb_tail_pointer(skb),
WCN36XX_PKT_SIZE,
DMA_FROM_DEVICE);
@@ -297,7 +298,7 @@ static int wcn36xx_dxe_ch_alloc_skb(struct wcn36xx *wcn,
cur_ctl = wcn_ch->head_blk_ctl;
for (i = 0; i < wcn_ch->desc_num; i++) {
- wcn36xx_dxe_fill_skb(cur_ctl);
+ wcn36xx_dxe_fill_skb(wcn->dev, cur_ctl);
cur_ctl = cur_ctl->next;
}
@@ -345,7 +346,7 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status)
static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
{
- struct wcn36xx_dxe_ctl *ctl = ch->tail_blk_ctl;
+ struct wcn36xx_dxe_ctl *ctl;
struct ieee80211_tx_info *info;
unsigned long flags;
@@ -354,23 +355,25 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
* completely full head and tail are pointing to the same element
* and while-do will not make any cycles.
*/
+ spin_lock_irqsave(&ch->lock, flags);
+ ctl = ch->tail_blk_ctl;
do {
if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
break;
if (ctl->skb) {
- dma_unmap_single(NULL, ctl->desc->src_addr_l,
+ dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
ctl->skb->len, DMA_TO_DEVICE);
info = IEEE80211_SKB_CB(ctl->skb);
if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
/* Keep frame until TX status comes */
ieee80211_free_txskb(wcn->hw, ctl->skb);
}
- spin_lock_irqsave(&ctl->skb_lock, flags);
+ spin_lock(&ctl->skb_lock);
if (wcn->queues_stopped) {
wcn->queues_stopped = false;
ieee80211_wake_queues(wcn->hw);
}
- spin_unlock_irqrestore(&ctl->skb_lock, flags);
+ spin_unlock(&ctl->skb_lock);
ctl->skb = NULL;
}
@@ -379,6 +382,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
!(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK));
ch->tail_blk_ctl = ctl;
+ spin_unlock_irqrestore(&ch->lock, flags);
}
static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
@@ -474,7 +478,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
skb = ctl->skb;
dma_addr = dxe->dst_addr_l;
- wcn36xx_dxe_fill_skb(ctl);
+ wcn36xx_dxe_fill_skb(wcn->dev, ctl);
switch (ch->ch_type) {
case WCN36XX_DXE_CH_RX_L:
@@ -491,7 +495,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
wcn36xx_warn("Unknown channel\n");
}
- dma_unmap_single(NULL, dma_addr, WCN36XX_PKT_SIZE,
+ dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
DMA_FROM_DEVICE);
wcn36xx_rx_skb(wcn, skb);
ctl = ctl->next;
@@ -540,7 +544,7 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
- cpu_addr = dma_alloc_coherent(NULL, s, &wcn->mgmt_mem_pool.phy_addr,
+ cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr,
GFP_KERNEL);
if (!cpu_addr)
goto out_err;
@@ -555,7 +559,7 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
- cpu_addr = dma_alloc_coherent(NULL, s, &wcn->data_mem_pool.phy_addr,
+ cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr,
GFP_KERNEL);
if (!cpu_addr)
goto out_err;
@@ -574,13 +578,13 @@ out_err:
void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn)
{
if (wcn->mgmt_mem_pool.virt_addr)
- dma_free_coherent(NULL, wcn->mgmt_mem_pool.chunk_size *
+ dma_free_coherent(wcn->dev, wcn->mgmt_mem_pool.chunk_size *
WCN36XX_DXE_CH_DESC_NUMB_TX_H,
wcn->mgmt_mem_pool.virt_addr,
wcn->mgmt_mem_pool.phy_addr);
if (wcn->data_mem_pool.virt_addr) {
- dma_free_coherent(NULL, wcn->data_mem_pool.chunk_size *
+ dma_free_coherent(wcn->dev, wcn->data_mem_pool.chunk_size *
WCN36XX_DXE_CH_DESC_NUMB_TX_L,
wcn->data_mem_pool.virt_addr,
wcn->data_mem_pool.phy_addr);
@@ -596,12 +600,14 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
struct wcn36xx_dxe_desc *desc = NULL;
struct wcn36xx_dxe_ch *ch = NULL;
unsigned long flags;
+ int ret;
ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch;
+ spin_lock_irqsave(&ch->lock, flags);
ctl = ch->head_blk_ctl;
- spin_lock_irqsave(&ctl->next->skb_lock, flags);
+ spin_lock(&ctl->next->skb_lock);
/*
* If skb is not null that means that we reached the tail of the ring
@@ -611,10 +617,11 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
if (NULL != ctl->next->skb) {
ieee80211_stop_queues(wcn->hw);
wcn->queues_stopped = true;
- spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
+ spin_unlock(&ctl->next->skb_lock);
+ spin_unlock_irqrestore(&ch->lock, flags);
return -EBUSY;
}
- spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
+ spin_unlock(&ctl->next->skb_lock);
ctl->skb = NULL;
desc = ctl->desc;
@@ -640,10 +647,11 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
desc = ctl->desc;
if (ctl->bd_cpu_addr) {
wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto unlock;
}
- desc->src_addr_l = dma_map_single(NULL,
+ desc->src_addr_l = dma_map_single(wcn->dev,
ctl->skb->data,
ctl->skb->len,
DMA_TO_DEVICE);
@@ -679,7 +687,10 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
ch->reg_ctrl, ch->def_ctrl);
}
- return 0;
+ ret = 0;
+unlock:
+ spin_unlock_irqrestore(&ch->lock, flags);
+ return ret;
}
int wcn36xx_dxe_init(struct wcn36xx *wcn)
@@ -696,7 +707,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/
/* Init descriptors for TX LOW channel */
/***************************************/
- wcn36xx_dxe_init_descs(&wcn->dxe_tx_l_ch);
+ wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_l_ch);
wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool);
/* Write channel head to a NEXT register */
@@ -714,7 +725,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/
/* Init descriptors for TX HIGH channel */
/***************************************/
- wcn36xx_dxe_init_descs(&wcn->dxe_tx_h_ch);
+ wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_tx_h_ch);
wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool);
/* Write channel head to a NEXT register */
@@ -734,7 +745,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/
/* Init descriptors for RX LOW channel */
/***************************************/
- wcn36xx_dxe_init_descs(&wcn->dxe_rx_l_ch);
+ wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_l_ch);
/* For RX we need to preallocated buffers */
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch);
@@ -764,7 +775,7 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
/***************************************/
/* Init descriptors for RX HIGH channel */
/***************************************/
- wcn36xx_dxe_init_descs(&wcn->dxe_rx_h_ch);
+ wcn36xx_dxe_init_descs(wcn->dev, &wcn->dxe_rx_h_ch);
/* For RX we need to prealocat buffers */
wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch);
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h
index 35ee7e966bd2..3eca4f9594f2 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.h
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.h
@@ -243,6 +243,7 @@ struct wcn36xx_dxe_ctl {
};
struct wcn36xx_dxe_ch {
+ spinlock_t lock; /* protects head/tail ptrs */
enum wcn36xx_dxe_ch_type ch_type;
void *cpu_addr;
dma_addr_t dma_addr;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 06fc46f85c85..50c136e843c4 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -236,7 +236,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
BIT_DMA_EP_RX_ICR_RX_HTRSH);
- if (likely(test_bit(wil_status_reset_done, wil->status))) {
+ if (likely(test_bit(wil_status_fwready, wil->status))) {
if (likely(test_bit(wil_status_napi_en, wil->status))) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
need_unmask = false;
@@ -286,7 +286,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
/* clear also all VRING interrupts */
isr &= ~(BIT(25) - 1UL);
- if (likely(test_bit(wil_status_reset_done, wil->status))) {
+ if (likely(test_bit(wil_status_fwready, wil->status))) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_tx);
@@ -364,7 +364,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
if (isr & ISR_MISC_FW_READY) {
wil_dbg_irq(wil, "IRQ: FW ready\n");
wil_cache_mbox_regs(wil);
- set_bit(wil_status_reset_done, wil->status);
+ set_bit(wil_status_mbox_ready, wil->status);
/**
* Actual FW ready indicated by the
* WMI_FW_READY_EVENTID
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index aade16b126c4..bb69a5949aea 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -422,7 +422,7 @@ static void wil_connect_worker(struct work_struct *work)
wil->sta[cid].status = wil_sta_connected;
netif_tx_wake_all_queues(ndev);
} else {
- wil->sta[cid].status = wil_sta_unused;
+ wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true);
}
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 0f8b6877497e..3bc9bc0efbac 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1242,6 +1242,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
int tcp_hdr_len;
int skb_net_hdr_len;
int gso_type;
+ int rc = -EINVAL;
wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n",
__func__, skb->len, vring_index);
@@ -1333,8 +1334,9 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
len, rem_data, descs_used);
if (descs_used == avail) {
- wil_err(wil, "TSO: ring overflow\n");
- goto dma_error;
+ wil_err_ratelimited(wil, "TSO: ring overflow\n");
+ rc = -ENOMEM;
+ goto mem_error;
}
lenmss = min_t(int, rem_data, len);
@@ -1356,8 +1358,10 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
headlen -= lenmss;
}
- if (unlikely(dma_mapping_error(dev, pa)))
- goto dma_error;
+ if (unlikely(dma_mapping_error(dev, pa))) {
+ wil_err(wil, "TSO: DMA map page error\n");
+ goto mem_error;
+ }
_desc = &vring->va[i].tx;
@@ -1456,8 +1460,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
}
/* advance swhead */
- wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
wil_vring_advance_head(vring, descs_used);
+ wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
/* make sure all writes to descriptors (shared memory) are done before
* committing them to HW
@@ -1467,8 +1471,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
wil_w(wil, vring->hwtail, vring->swhead);
return 0;
-dma_error:
- wil_err(wil, "TSO: DMA map page error\n");
+mem_error:
while (descs_used > 0) {
struct wil_ctx *ctx;
@@ -1479,14 +1482,11 @@ dma_error:
_desc->dma.status = TX_DMA_STATUS_DU;
ctx = &vring->ctx[i];
wil_txdesc_unmap(dev, d, ctx);
- if (ctx->skb)
- dev_kfree_skb_any(ctx->skb);
memset(ctx, 0, sizeof(*ctx));
descs_used--;
}
-
err_exit:
- return -EINVAL;
+ return rc;
}
static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
@@ -1562,8 +1562,11 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
_d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(dev, pa)))
+ if (unlikely(dma_mapping_error(dev, pa))) {
+ wil_err(wil, "Tx[%2d] failed to map fragment\n",
+ vring_index);
goto dma_error;
+ }
vring->ctx[i].mapped_as = wil_mapped_as_page;
wil_tx_desc_map(d, pa, len, vring_index);
/* no need to check return code -
@@ -1623,9 +1626,6 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
_d->dma.status = TX_DMA_STATUS_DU;
wil_txdesc_unmap(dev, d, ctx);
- if (ctx->skb)
- dev_kfree_skb_any(ctx->skb);
-
memset(ctx, 0, sizeof(*ctx));
}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index f619bf234353..ade5f3b8274b 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -402,11 +402,11 @@ struct vring_tx_data {
};
enum { /* for wil6210_priv.status */
- wil_status_fwready = 0,
+ wil_status_fwready = 0, /* FW operational */
wil_status_fwconnecting,
wil_status_fwconnected,
wil_status_dontscan,
- wil_status_reset_done,
+ wil_status_mbox_ready, /* MBOX structures ready */
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
wil_status_resetting, /* reset in progress */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 61121892c6ca..6ed26baca0e5 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -293,12 +293,6 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
/* ignore MAC address, we already have it from the boot loader */
snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
"%d", wil->fw_version);
-}
-
-static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
- int len)
-{
- wil_dbg_wmi(wil, "WMI: got FW ready event\n");
wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_fwready, wil->status);
@@ -684,13 +678,22 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
spin_unlock_bh(&sta->tid_rx_lock);
}
+/**
+ * Some events are ignored for purpose; and need not be interpreted as
+ * "unhandled events"
+ */
+static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
+{
+ wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
+}
+
static const struct {
int eventid;
void (*handler)(struct wil6210_priv *wil, int eventid,
void *data, int data_len);
} wmi_evt_handlers[] = {
{WMI_READY_EVENTID, wmi_evt_ready},
- {WMI_FW_READY_EVENTID, wmi_evt_fw_ready},
+ {WMI_FW_READY_EVENTID, wmi_evt_ignore},
{WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
{WMI_TX_MGMT_PACKET_EVENTID, wmi_evt_tx_mgmt},
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
@@ -701,6 +704,7 @@ static const struct {
{WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
{WMI_DELBA_EVENTID, wmi_evt_delba},
{WMI_VRING_EN_EVENTID, wmi_evt_vring_en},
+ {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
};
/*
@@ -720,7 +724,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
ulong flags;
unsigned n;
- if (!test_bit(wil_status_reset_done, wil->status)) {
+ if (!test_bit(wil_status_mbox_ready, wil->status)) {
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 759fb8d41fc9..fba856032ca5 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -71,26 +71,6 @@ config B43_PCICORE_AUTOSELECT
select SSB_DRIVER_PCICORE
default y
-config B43_PCMCIA
- bool "Broadcom 43xx PCMCIA device support"
- depends on B43 && B43_SSB && SSB_PCMCIAHOST_POSSIBLE
- select SSB_PCMCIAHOST
- ---help---
- Broadcom 43xx PCMCIA device support.
-
- Support for 16bit PCMCIA devices.
- Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
- devices, but 32bit CardBUS devices. CardBUS devices are supported
- out of the box by b43.
-
- With this config option you can drive b43 cards in
- CompactFlash formfactor in a PCMCIA adaptor.
- CF b43 cards can sometimes be found in handheld PCs.
-
- It's safe to select Y here, even if you don't have a B43 PCMCIA device.
-
- If unsure, say N.
-
config B43_SDIO
bool "Broadcom 43xx SDIO device support"
depends on B43 && B43_SSB && SSB_SDIOHOST_POSSIBLE
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index c624d4d90e4f..ddc4df46656f 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -21,7 +21,6 @@ b43-y += pio.o
b43-y += rfkill.o
b43-y += ppr.o
b43-$(CONFIG_B43_LEDS) += leds.o
-b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
b43-$(CONFIG_B43_SDIO) += sdio.o
b43-$(CONFIG_B43_DEBUG) += debugfs.o
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 71d3e9adbf3c..ec013fbd6a81 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -56,7 +56,6 @@
#include "sysfs.h"
#include "xmit.h"
#include "lo.h"
-#include "pcmcia.h"
#include "sdio.h"
#include <linux/mmc/sdio_func.h>
@@ -5850,12 +5849,9 @@ static int __init b43_init(void)
int err;
b43_debugfs_init();
- err = b43_pcmcia_init();
- if (err)
- goto err_dfs_exit;
err = b43_sdio_init();
if (err)
- goto err_pcmcia_exit;
+ goto err_dfs_exit;
#ifdef CONFIG_B43_BCMA
err = bcma_driver_register(&b43_bcma_driver);
if (err)
@@ -5878,8 +5874,6 @@ err_bcma_driver_exit:
err_sdio_exit:
#endif
b43_sdio_exit();
-err_pcmcia_exit:
- b43_pcmcia_exit();
err_dfs_exit:
b43_debugfs_exit();
return err;
@@ -5894,7 +5888,6 @@ static void __exit b43_exit(void)
bcma_driver_unregister(&b43_bcma_driver);
#endif
b43_sdio_exit();
- b43_pcmcia_exit();
b43_debugfs_exit();
}
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
deleted file mode 100644
index 55f2bd7f8f74..000000000000
--- a/drivers/net/wireless/b43/pcmcia.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-
- Broadcom B43 wireless driver
-
- Copyright (c) 2007 Michael Buesch <m@bues.ch>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
-*/
-
-#include "pcmcia.h"
-
-#include <linux/ssb/ssb.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-
-static const struct pcmcia_device_id b43_pcmcia_tbl[] = {
- PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
- PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
- PCMCIA_DEVICE_NULL,
-};
-
-MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
-
-#ifdef CONFIG_PM
-static int b43_pcmcia_suspend(struct pcmcia_device *dev)
-{
- struct ssb_bus *ssb = dev->priv;
-
- return ssb_bus_suspend(ssb);
-}
-
-static int b43_pcmcia_resume(struct pcmcia_device *dev)
-{
- struct ssb_bus *ssb = dev->priv;
-
- return ssb_bus_resume(ssb);
-}
-#else /* CONFIG_PM */
-# define b43_pcmcia_suspend NULL
-# define b43_pcmcia_resume NULL
-#endif /* CONFIG_PM */
-
-static int b43_pcmcia_probe(struct pcmcia_device *dev)
-{
- struct ssb_bus *ssb;
- int err = -ENOMEM;
- int res = 0;
-
- ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
- if (!ssb)
- goto out_error;
-
- err = -ENODEV;
-
- dev->config_flags |= CONF_ENABLE_IRQ;
-
- dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 |
- WIN_USE_WAIT;
- dev->resource[2]->start = 0;
- dev->resource[2]->end = SSB_CORE_SIZE;
- res = pcmcia_request_window(dev, dev->resource[2], 250);
- if (res != 0)
- goto err_kfree_ssb;
-
- res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
- if (res != 0)
- goto err_disable;
-
- if (!dev->irq)
- goto err_disable;
-
- res = pcmcia_enable_device(dev);
- if (res != 0)
- goto err_disable;
-
- err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
- if (err)
- goto err_disable;
- dev->priv = ssb;
-
- return 0;
-
-err_disable:
- pcmcia_disable_device(dev);
-err_kfree_ssb:
- kfree(ssb);
-out_error:
- printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
- res, err);
- return err;
-}
-
-static void b43_pcmcia_remove(struct pcmcia_device *dev)
-{
- struct ssb_bus *ssb = dev->priv;
-
- ssb_bus_unregister(ssb);
- pcmcia_disable_device(dev);
- kfree(ssb);
- dev->priv = NULL;
-}
-
-static struct pcmcia_driver b43_pcmcia_driver = {
- .owner = THIS_MODULE,
- .name = "b43-pcmcia",
- .id_table = b43_pcmcia_tbl,
- .probe = b43_pcmcia_probe,
- .remove = b43_pcmcia_remove,
- .suspend = b43_pcmcia_suspend,
- .resume = b43_pcmcia_resume,
-};
-
-/*
- * These are not module init/exit functions!
- * The module_pcmcia_driver() helper cannot be used here.
- */
-int b43_pcmcia_init(void)
-{
- return pcmcia_register_driver(&b43_pcmcia_driver);
-}
-
-void b43_pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&b43_pcmcia_driver);
-}
diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h
deleted file mode 100644
index 85f120a67cbe..000000000000
--- a/drivers/net/wireless/b43/pcmcia.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef B43_PCMCIA_H_
-#define B43_PCMCIA_H_
-
-#ifdef CONFIG_B43_PCMCIA
-
-int b43_pcmcia_init(void);
-void b43_pcmcia_exit(void);
-
-#else /* CONFIG_B43_PCMCIA */
-
-static inline int b43_pcmcia_init(void)
-{
- return 0;
-}
-static inline void b43_pcmcia_exit(void)
-{
-}
-
-#endif /* CONFIG_B43_PCMCIA */
-#endif /* B43_PCMCIA_H_ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index af5b3201492c..9dbe19cbb4dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -86,6 +86,8 @@
* Structured as &struct iwl_fw_error_dump_trigger_desc.
* @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as
* &struct iwl_fw_error_dump_rb
+ * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were
+ * paged to the DRAM.
*/
enum iwl_fw_error_dump_type {
/* 0 is deprecated */
@@ -100,6 +102,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_MEM = 9,
IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
IWL_FW_ERROR_DUMP_RB = 11,
+ IWL_FW_ERROR_DUMP_PAGING = 12,
IWL_FW_ERROR_DUMP_MAX,
};
@@ -240,6 +243,19 @@ struct iwl_fw_error_dump_rb {
};
/**
+ * struct iwl_fw_error_dump_paging - content of the UMAC's image page
+ * block on DRAM
+ * @index: the index of the page block
+ * @reserved:
+ * @data: the content of the page block
+ */
+struct iwl_fw_error_dump_paging {
+ __le32 index;
+ __le32 reserved;
+ u8 data[];
+};
+
+/**
* iwl_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block
* Returns: next data block
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 72ddd4a163e6..08303db0000f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -306,6 +306,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
* is supported.
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
* @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan
+ * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
+ * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
*
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/
@@ -330,6 +332,8 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29,
IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30,
IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31,
+ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
+ IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index bb51b6f8002c..6f76525088f0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -409,6 +409,7 @@ enum iwl_d3_status {
* @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands
* are sent
* @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent
+ * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation
*/
enum iwl_trans_status {
STATUS_SYNC_HCMD_ACTIVE,
@@ -419,6 +420,7 @@ enum iwl_trans_status {
STATUS_FW_ERROR,
STATUS_TRANS_GOING_IDLE,
STATUS_TRANS_IDLE,
+ STATUS_TRANS_DEAD,
};
/**
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index a3ca6db0f303..5c21231e195d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -71,6 +71,9 @@
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
#define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC)
+#define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */
+#define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */
+#define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 0
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
@@ -101,7 +104,6 @@
#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0
#define IWL_MVM_QUOTA_THRESHOLD 4
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
-#define IWL_MVM_RS_DISABLE_P2P_MIMO 0
#define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1
#define IWL_MVM_TOF_IS_RESPONDER 0
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 398bef6f4f61..7904b41a04c6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -715,11 +715,30 @@ static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
goto out;
}
- data = iwl_dbgfs_is_match("ctrl_ch_position=", buf);
+ data = iwl_dbgfs_is_match("center_freq=", buf);
if (data) {
+ struct iwl_tof_responder_config_cmd *cmd =
+ &mvm->tof_data.responder_cfg;
+
ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.ctrl_ch_position = value;
+ if (ret == 0 && value) {
+ enum ieee80211_band band = (cmd->channel_num <= 14) ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ;
+ struct ieee80211_channel chn = {
+ .band = band,
+ .center_freq = ieee80211_channel_to_frequency(
+ cmd->channel_num, band),
+ };
+ struct cfg80211_chan_def chandef = {
+ .chan = &chn,
+ .center_freq1 =
+ ieee80211_channel_to_frequency(value,
+ band),
+ };
+
+ cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
+ }
goto out;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 9b4fbb8b483a..05928fb4021d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -85,7 +85,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
+ ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, 0) ? : count;
mutex_unlock(&mvm->mutex);
return ret;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 660cc1c93e19..3a657e4b60ac 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -101,6 +101,7 @@ struct iwl_ssid_ie {
#define IWL_FULL_SCAN_MULTIPLIER 5
#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
+#define IWL_MAX_SCHED_SCAN_PLANS 2
enum scan_framework_client {
SCAN_CLIENT_SCHED_SCAN = BIT(0),
@@ -359,7 +360,7 @@ struct iwl_scan_req_lmac {
/* SCAN_REQ_PERIODIC_PARAMS_API_S */
__le32 iter_num;
__le32 delay;
- struct iwl_scan_schedule_lmac schedule[2];
+ struct iwl_scan_schedule_lmac schedule[IWL_MAX_SCHED_SCAN_PLANS];
struct iwl_scan_channel_opt channel_opt[2];
u8 data[];
} __packed;
@@ -582,7 +583,7 @@ struct iwl_scan_umac_schedule {
*/
struct iwl_scan_req_umac_tail {
/* SCAN_PERIODIC_PARAMS_API_S_VER_1 */
- struct iwl_scan_umac_schedule schedule[2];
+ struct iwl_scan_umac_schedule schedule[IWL_MAX_SCHED_SCAN_PLANS];
__le16 delay;
__le16 reserved;
/* SCAN_PROBE_PARAMS_API_S_VER_1 */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 44ff6849b7a5..181590fbd3b3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1524,6 +1524,69 @@ struct iwl_dts_measurement_cmd {
} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */
/**
+* enum iwl_dts_control_measurement_mode - DTS measurement type
+* @DTS_AUTOMATIC: Automatic mode (full SW control). Provide temperature read
+* back (latest value. Not waiting for new value). Use automatic
+* SW DTS configuration.
+* @DTS_REQUEST_READ: Request DTS read. Configure DTS with manual settings,
+* trigger DTS reading and provide read back temperature read
+* when available.
+* @DTS_OVER_WRITE: over-write the DTS temperatures in the SW until next read
+* @DTS_DIRECT_WITHOUT_MEASURE: DTS returns its latest temperature result,
+* without measurement trigger.
+*/
+enum iwl_dts_control_measurement_mode {
+ DTS_AUTOMATIC = 0,
+ DTS_REQUEST_READ = 1,
+ DTS_OVER_WRITE = 2,
+ DTS_DIRECT_WITHOUT_MEASURE = 3,
+};
+
+/**
+* enum iwl_dts_used - DTS to use or used for measurement in the DTS request
+* @DTS_USE_TOP: Top
+* @DTS_USE_CHAIN_A: chain A
+* @DTS_USE_CHAIN_B: chain B
+* @DTS_USE_CHAIN_C: chain C
+* @XTAL_TEMPERATURE - read temperature from xtal
+*/
+enum iwl_dts_used {
+ DTS_USE_TOP = 0,
+ DTS_USE_CHAIN_A = 1,
+ DTS_USE_CHAIN_B = 2,
+ DTS_USE_CHAIN_C = 3,
+ XTAL_TEMPERATURE = 4,
+};
+
+/**
+* enum iwl_dts_bit_mode - bit-mode to use in DTS request read mode
+* @DTS_BIT6_MODE: bit 6 mode
+* @DTS_BIT8_MODE: bit 8 mode
+*/
+enum iwl_dts_bit_mode {
+ DTS_BIT6_MODE = 0,
+ DTS_BIT8_MODE = 1,
+};
+
+/**
+ * iwl_ext_dts_measurement_cmd - request extended DTS temperature measurements
+ * @control_mode: see &enum iwl_dts_control_measurement_mode
+ * @temperature: used when over write DTS mode is selected
+ * @sensor: set temperature sensor to use. See &enum iwl_dts_used
+ * @avg_factor: average factor to DTS in request DTS read mode
+ * @bit_mode: value defines the DTS bit mode to use. See &enum iwl_dts_bit_mode
+ * @step_duration: step duration for the DTS
+ */
+struct iwl_ext_dts_measurement_cmd {
+ __le32 control_mode;
+ __le32 temperature;
+ __le32 sensor;
+ __le32 avg_factor;
+ __le32 bit_mode;
+ __le32 step_duration;
+} __packed; /* XVT_FW_DTS_CONTROL_MEASUREMENT_REQUEST_API_S */
+
+/**
* iwl_dts_measurement_notif - notification received with the measurements
*
* @temp: the measured temperature
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 9d36ba7295a5..ad7ad720d2e7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -843,6 +843,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval);
ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid);
+ if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p)
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
+
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index a38e07bb137f..1fb684693040 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -572,6 +572,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
/* we create the 802.11 header and zero length SSID IE. */
hw->wiphy->max_sched_scan_ie_len =
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
+ hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
+ hw->wiphy->max_sched_scan_plan_interval = U16_MAX;
+
+ /*
+ * the firmware uses u8 for num of iterations, but 0xff is saved for
+ * infinite loop, so the maximum number of iterations is actually 254.
+ */
+ hw->wiphy->max_sched_scan_plan_iterations = 254;
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -1129,6 +1137,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
+ /* there's no point in fw dump if the bus is dead */
+ if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) {
+ IWL_ERR(mvm, "Skip fw error dump since bus is dead\n");
+ return;
+ }
+
if (mvm->fw_dump_trig &&
mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)
monitor_dump_only = true;
@@ -1192,6 +1206,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
if (sram2_len)
file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
+ /* Make room for fw's virtual image pages, if it exists */
+ if (mvm->fw->img[mvm->cur_ucode].paging_mem_size)
+ file_len += mvm->num_of_paging_blk *
+ (sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_paging) +
+ PAGING_BLOCK_SIZE);
+
/* If we only want a monitor dump, reset the file length */
if (monitor_dump_only) {
file_len = sizeof(*dump_file) + sizeof(*dump_data) +
@@ -1302,6 +1323,26 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_mem->data, IWL8260_ICCM_LEN);
}
+ /* Dump fw's virtual image */
+ if (mvm->fw->img[mvm->cur_ucode].paging_mem_size) {
+ u32 i;
+
+ for (i = 1; i < mvm->num_of_paging_blk + 1; i++) {
+ struct iwl_fw_error_dump_paging *paging;
+ struct page *pages =
+ mvm->fw_paging_db[i].fw_paging_block;
+
+ dump_data = iwl_fw_error_next_data(dump_data);
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
+ dump_data->len = cpu_to_le32(sizeof(*paging) +
+ PAGING_BLOCK_SIZE);
+ paging = (void *)dump_data->data;
+ paging->index = cpu_to_le32(i);
+ memcpy(paging->data, page_address(pages),
+ PAGING_BLOCK_SIZE);
+ }
+ }
+
dump_trans_data:
fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans,
mvm->fw_dump_trig);
@@ -1754,7 +1795,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
* Flush them here.
*/
mutex_lock(&mvm->mutex);
- iwl_mvm_flush_tx_path(mvm, tfd_msk, true);
+ iwl_mvm_flush_tx_path(mvm, tfd_msk, 0);
mutex_unlock(&mvm->mutex);
/*
@@ -1955,6 +1996,27 @@ out:
*total_flags = 0;
}
+static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ unsigned int filter_flags,
+ unsigned int changed_flags)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ /* We support only filter for probe requests */
+ if (!(changed_flags & FIF_PROBE_REQ))
+ return;
+
+ /* Supported only for p2p client interfaces */
+ if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc ||
+ !vif->p2p)
+ return;
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ mutex_unlock(&mvm->mutex);
+}
+
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
struct iwl_bcast_iter_data {
struct iwl_mvm *mvm;
@@ -3898,7 +3960,7 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
}
if (drop) {
- if (iwl_mvm_flush_tx_path(mvm, msk, true))
+ if (iwl_mvm_flush_tx_path(mvm, msk, 0))
IWL_ERR(mvm, "flush request fail\n");
mutex_unlock(&mvm->mutex);
} else {
@@ -4135,6 +4197,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.config = iwl_mvm_mac_config,
.prepare_multicast = iwl_mvm_prepare_multicast,
.configure_filter = iwl_mvm_configure_filter,
+ .config_iface_filter = iwl_mvm_config_iface_filter,
.bss_info_changed = iwl_mvm_bss_info_changed,
.hw_scan = iwl_mvm_mac_hw_scan,
.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 16c5a6d7e0c9..c6327cd1d071 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -1036,7 +1036,7 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status);
#else
static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
#endif
-int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info,
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 4e4a680f274a..2ee0f6fe56a1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -483,6 +483,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
ret = -ENOMEM;
break;
}
+ kfree(mvm->nvm_sections[section_id].data);
mvm->nvm_sections[section_id].data = temp;
mvm->nvm_sections[section_id].length = section_size;
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 723b537341c4..bed9696ee410 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -348,7 +348,8 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_mac_power_cmd *cmd)
+ struct iwl_mac_power_cmd *cmd,
+ bool host_awake)
{
int dtimper, bi;
int keep_alive;
@@ -376,8 +377,13 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
- if (!vif->bss_conf.ps || !mvmvif->pm_enabled ||
- (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p))
+ if (!vif->bss_conf.ps || !mvmvif->pm_enabled)
+ return;
+
+ if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
+ (!fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS) ||
+ !IWL_MVM_P2P_LOWLATENCY_PS_ENABLE))
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -389,19 +395,25 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD;
}
- iwl_mvm_power_config_skip_dtim(mvm, vif, cmd,
- mvm->cur_ucode != IWL_UCODE_WOWLAN);
+ iwl_mvm_power_config_skip_dtim(mvm, vif, cmd, host_awake);
- if (mvm->cur_ucode != IWL_UCODE_WOWLAN) {
+ if (!host_awake) {
cmd->rx_data_timeout =
- cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
cmd->tx_data_timeout =
- cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+ } else if (iwl_mvm_vif_low_latency(mvmvif) && vif->p2p &&
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS)) {
+ cmd->tx_data_timeout =
+ cpu_to_le32(IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT);
+ cmd->rx_data_timeout =
+ cpu_to_le32(IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT);
} else {
cmd->rx_data_timeout =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
+ cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);
cmd->tx_data_timeout =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+ cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);
}
if (iwl_mvm_power_allow_uapsd(mvm, vif))
@@ -458,7 +470,8 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
{
struct iwl_mac_power_cmd cmd = {};
- iwl_mvm_power_build_cmd(mvm, vif, &cmd);
+ iwl_mvm_power_build_cmd(mvm, vif, &cmd,
+ mvm->cur_ucode != IWL_UCODE_WOWLAN);
iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));
@@ -994,11 +1007,7 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
if (!vif->bss_conf.assoc)
return 0;
- iwl_mvm_power_build_cmd(mvm, vif, &cmd);
-
- /* when enabling D0i3, override the skip-over-dtim configuration */
- if (enable)
- iwl_mvm_power_config_skip_dtim(mvm, vif, &cmd, false);
+ iwl_mvm_power_build_cmd(mvm, vif, &cmd, !enable);
iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 34d98b26a215..d1ad10391b47 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -177,9 +177,6 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
- if (IWL_MVM_RS_DISABLE_P2P_MIMO &&
- iwl_mvm_vif_low_latency(mvmvif) && mvmsta->vif->p2p)
- return false;
if (mvm->nvm_data->sku_cap_mimo_disabled)
return false;
@@ -3071,9 +3068,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
else
rs_vht_init(mvm, sta, lq_sta, vht_cap);
- if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p)
- lq_sta->active_mimo2_rate = 0;
-
lq_sta->max_legacy_rate_idx =
rs_get_max_rate_from_mask(lq_sta->active_legacy_rate);
lq_sta->max_siso_rate_idx =
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index cee4f267ca66..d6e0c1b5c20c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -131,7 +131,6 @@ struct iwl_mvm_scan_params {
int n_ssids;
struct cfg80211_ssid *ssids;
struct ieee80211_channel **channels;
- u16 interval; /* interval between scans (in secs) */
u32 flags;
u8 *mac_addr;
u8 *mac_addr_mask;
@@ -140,7 +139,8 @@ struct iwl_mvm_scan_params {
int n_match_sets;
struct iwl_scan_probe_req preq;
struct cfg80211_match_set *match_sets;
- u8 iterations[2];
+ int n_scan_plans;
+ struct cfg80211_sched_scan_plan *scan_plans;
};
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
@@ -474,7 +474,7 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
int ret;
if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES))
- return -EIO;
+ return -EIO;
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL)
blacklist_len = IWL_SCAN_SHORT_BLACKLIST_LEN;
@@ -737,8 +737,7 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
}
static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- int n_iterations)
+ struct ieee80211_vif *vif)
{
const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;
@@ -753,11 +752,6 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
vif->type != NL80211_IFTYPE_P2P_DEVICE);
}
-static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)
-{
- return params->iterations[0] + params->iterations[1];
-}
-
static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params)
{
@@ -796,12 +790,15 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
(void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
mvm->fw->ucode_capa.n_scan_channels);
u32 ssid_bitmap = 0;
- int n_iterations = iwl_mvm_scan_total_iterations(params);
+ int i;
lockdep_assert_held(&mvm->mutex);
memset(cmd, 0, ksize(cmd));
+ if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
+ return -EINVAL;
+
iwl_mvm_scan_lmac_dwell(mvm, cmd, params);
cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
@@ -821,14 +818,26 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* this API uses bits 1-20 instead of 0-19 */
ssid_bitmap <<= 1;
- cmd->schedule[0].delay = cpu_to_le16(params->interval);
- cmd->schedule[0].iterations = params->iterations[0];
- cmd->schedule[0].full_scan_mul = 1;
- cmd->schedule[1].delay = cpu_to_le16(params->interval);
- cmd->schedule[1].iterations = params->iterations[1];
- cmd->schedule[1].full_scan_mul = 1;
+ for (i = 0; i < params->n_scan_plans; i++) {
+ struct cfg80211_sched_scan_plan *scan_plan =
+ &params->scan_plans[i];
+
+ cmd->schedule[i].delay =
+ cpu_to_le16(scan_plan->interval);
+ cmd->schedule[i].iterations = scan_plan->iterations;
+ cmd->schedule[i].full_scan_mul = 1;
+ }
+
+ /*
+ * If the number of iterations of the last scan plan is set to
+ * zero, it should run infinitely. However, this is not always the case.
+ * For example, when regular scan is requested the driver sets one scan
+ * plan with one iteration.
+ */
+ if (!cmd->schedule[i - 1].iterations)
+ cmd->schedule[i - 1].iterations = 0xff;
- if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {
+ if (iwl_mvm_scan_use_ebs(mvm, vif)) {
cmd->channel_opt[0].flags =
cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
@@ -892,7 +901,6 @@ static __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm)
int iwl_mvm_config_scan(struct iwl_mvm *mvm)
{
-
struct iwl_scan_config *scan_config;
struct ieee80211_supported_band *band;
int num_channels =
@@ -968,6 +976,12 @@ static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status)
return -ENOENT;
}
+static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
+{
+ return params->n_scan_plans == 1 &&
+ params->scan_plans[0].iterations == 1;
+}
+
static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
@@ -980,7 +994,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
cmd->scan_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
- if (iwl_mvm_scan_total_iterations(params) == 1)
+ if (iwl_mvm_is_regular_scan(params))
cmd->ooc_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
else
@@ -1027,7 +1041,7 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
else
flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
- if (iwl_mvm_scan_total_iterations(params) > 1)
+ if (!iwl_mvm_is_regular_scan(params))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1045,12 +1059,14 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels;
- int uid;
+ int uid, i;
u32 ssid_bitmap = 0;
- int n_iterations = iwl_mvm_scan_total_iterations(params);
lockdep_assert_held(&mvm->mutex);
+ if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
+ return -EINVAL;
+
uid = iwl_mvm_scan_uid_by_status(mvm, 0);
if (uid < 0)
return uid;
@@ -1067,7 +1083,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (type == IWL_MVM_SCAN_SCHED)
cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
- if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
+ if (iwl_mvm_scan_use_ebs(mvm, vif))
cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
@@ -1079,12 +1095,23 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_umac_scan_cfg_channels(mvm, params->channels,
params->n_channels, ssid_bitmap, cmd);
- /* With UMAC we use only one schedule for now, so use the sum
- * of the iterations (with a a maximum of 255).
+ for (i = 0; i < params->n_scan_plans; i++) {
+ struct cfg80211_sched_scan_plan *scan_plan =
+ &params->scan_plans[i];
+
+ sec_part->schedule[i].iter_count = scan_plan->iterations;
+ sec_part->schedule[i].interval =
+ cpu_to_le16(scan_plan->interval);
+ }
+
+ /*
+ * If the number of iterations of the last scan plan is set to
+ * zero, it should run infinitely. However, this is not always the case.
+ * For example, when regular scan is requested the driver sets one scan
+ * plan with one iteration.
*/
- sec_part->schedule[0].iter_count =
- (n_iterations > 255) ? 255 : n_iterations;
- sec_part->schedule[0].interval = cpu_to_le16(params->interval);
+ if (!sec_part->schedule[i - 1].iter_count)
+ sec_part->schedule[i - 1].iter_count = 0xff;
sec_part->delay = cpu_to_le16(params->delay);
sec_part->preq = params->preq;
@@ -1150,6 +1177,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
};
struct iwl_mvm_scan_params params = {};
int ret;
+ struct cfg80211_sched_scan_plan scan_plan = { .iterations = 1 };
lockdep_assert_held(&mvm->mutex);
@@ -1162,8 +1190,6 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (ret)
return ret;
- iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
-
/* we should have failed registration if scan_cmd was NULL */
if (WARN_ON(!mvm->scan_cmd))
return -ENOMEM;
@@ -1175,7 +1201,6 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
params.flags = req->flags;
params.n_channels = req->n_channels;
params.delay = 0;
- params.interval = 0;
params.ssids = req->ssids;
params.channels = req->channels;
params.mac_addr = req->mac_addr;
@@ -1185,8 +1210,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
params.n_match_sets = 0;
params.match_sets = NULL;
- params.iterations[0] = 1;
- params.iterations[1] = 0;
+ params.scan_plans = &scan_plan;
+ params.n_scan_plans = 1;
params.type = iwl_mvm_get_scan_type(mvm, vif, &params);
@@ -1205,21 +1230,20 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return ret;
ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (!ret) {
- IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
- mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
- } else {
+ if (ret) {
/* If the scan failed, it usually means that the FW was unable
* to allocate the time events. Warn on it, but maybe we
* should try to send the command again with different params.
*/
IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
+ return ret;
}
- if (ret)
- iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+ IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+ mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
+ iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
- return ret;
+ return 0;
}
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
@@ -1265,20 +1289,14 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
params.pass_all = iwl_mvm_scan_pass_all(mvm, req);
params.n_match_sets = req->n_match_sets;
params.match_sets = req->match_sets;
+ if (!req->n_scan_plans)
+ return -EINVAL;
- params.iterations[0] = 0;
- params.iterations[1] = 0xff;
+ params.n_scan_plans = req->n_scan_plans;
+ params.scan_plans = req->scan_plans;
params.type = iwl_mvm_get_scan_type(mvm, vif, &params);
- if (req->scan_plans[0].interval > U16_MAX) {
- IWL_DEBUG_SCAN(mvm,
- "interval value is > 16-bits, set to max possible\n");
- params.interval = U16_MAX;
- } else {
- params.interval = req->scan_plans[0].interval;
- }
-
/* In theory, LMAC scans can handle a 32-bit delay, but since
* waiting for over 18 hours to start the scan is a bit silly
* and to keep it aligned with UMAC scans (which only support
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index a9a3eb6a1f8a..300a249486e4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -255,7 +255,7 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
/* disable the TDLS STA-specific queues */
sta_msk = mvmsta->tfd_queue_msk;
for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
- iwl_mvm_disable_txq(mvm, i, i, 0, 0);
+ iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0);
}
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
@@ -474,7 +474,8 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
unsigned long i, msk = mvm->tfd_drained[sta_id];
for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
- iwl_mvm_disable_txq(mvm, i, i, 0, 0);
+ iwl_mvm_disable_txq(mvm, i, i,
+ IWL_MAX_TID_COUNT, 0);
mvm->tfd_drained[sta_id] = 0;
IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
@@ -501,7 +502,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (ret)
return ret;
/* flush its queues here since we are freeing mvm_sta */
- ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
+ ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, 0);
if (ret)
return ret;
ret = iwl_trans_wait_tx_queue_empty(mvm->trans,
@@ -1155,7 +1156,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (old_state >= IWL_AGG_ON) {
iwl_mvm_drain_sta(mvm, mvmsta, true);
- if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+ if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
iwl_trans_wait_tx_queue_empty(mvm->trans,
mvmsta->tfd_queue_msk);
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index dbd7d544575d..7530eb23035d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -129,7 +129,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* issue as it will have to complete before the next command is
* executed, and a new time event means a new command.
*/
- iwl_mvm_flush_tx_path(mvm, queues, false);
+ iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC);
}
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 58b762f1e0b5..cadfc0460597 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -176,6 +176,9 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
struct iwl_dts_measurement_cmd cmd = {
.flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
};
+ struct iwl_ext_dts_measurement_cmd extcmd = {
+ .control_mode = cpu_to_le32(DTS_AUTOMATIC),
+ };
u32 cmdid;
if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
@@ -183,8 +186,12 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
PHY_OPS_GROUP, 0);
else
cmdid = CMD_DTS_MEASUREMENT_TRIGGER;
- return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0,
- sizeof(cmd), &cmd);
+
+ if (!fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE))
+ return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd);
+
+ return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
}
int iwl_mvm_get_temp(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index ff8b9bdef7e8..c652a66be803 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -1099,7 +1099,7 @@ out:
* 2) flush the Tx path
* 3) wait for the transport queues to be empty
*/
-int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags)
{
int ret;
struct iwl_tx_path_flush_cmd flush_cmd = {
@@ -1107,8 +1107,6 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
.flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
};
- u32 flags = sync ? 0 : CMD_ASYNC;
-
ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
sizeof(flush_cmd), &flush_cmd);
if (ret)
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 6ba7d300b08f..90283453073c 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -592,10 +592,8 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
do {
ret = iwl_pcie_set_hw_ready(trans);
- if (ret >= 0) {
- ret = 0;
- goto out;
- }
+ if (ret >= 0)
+ return 0;
usleep_range(200, 1000);
t += 200;
@@ -605,10 +603,6 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
IWL_ERR(trans, "Couldn't prepare the card\n");
-out:
- iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
- CSR_RESET_LINK_PWR_MGMT_DISABLED);
-
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index b7ac45f324d7..4073116e6e9f 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1821,6 +1821,10 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
return -1;
}
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+
return 0;
}
@@ -1925,6 +1929,10 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
if (mwifiex_set_mgmt_ies(priv, &params->beacon))
return -1;
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ mwifiex_wake_up_net_dev_queue(priv->netdev, priv->adapter);
+
memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg));
kfree(bss_cfg);
return 0;
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index 078834cf1251..86ff54296f39 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -179,19 +179,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
priv->port_open = false;
- if (netif_carrier_ok(priv->netdev))
- netif_carrier_off(priv->netdev);
- mwifiex_stop_net_dev_queue(priv->netdev, adapter);
-
mwifiex_clean_txrx(priv);
mwifiex_del_all_sta_list(priv);
break;
case EVENT_UAP_BSS_ACTIVE:
priv->media_connected = true;
priv->port_open = true;
- if (!netif_carrier_ok(priv->netdev))
- netif_carrier_on(priv->netdev);
- mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
break;
case EVENT_UAP_BSS_START:
mwifiex_dbg(adapter, EVENT,
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 26a57d773d30..f2cd513d54b2 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1576,6 +1576,7 @@ static int ezusb_probe(struct usb_interface *interface,
ezusb_hard_reset, NULL);
if (!priv) {
err("Couldn't allocate orinocodev");
+ retval = -ENOMEM;
goto exit;
}
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index f0d22cdb51cd..149214beeda9 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -80,6 +80,15 @@ config SSB_SDIOHOST
If unsure, say N
+config SSB_HOST_SOC
+ bool "Support for SSB bus on SoC"
+ depends on SSB
+ help
+ Host interface for a SSB directly mapped into memory. This is
+ for some Broadcom SoCs from the BCM47xx and BCM53xx lines.
+
+ If unsure, say N
+
config SSB_SILENT
bool "No SSB kernel messages"
depends on SSB && EXPERT
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
index b1ddc116d387..64a09681cee0 100644
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -5,8 +5,9 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o
# host support
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
-ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
+ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o bridge_pcmcia_80211.o
ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
+ssb-$(CONFIG_SSB_HOST_SOC) += host_soc.o
# built-in drivers
ssb-y += driver_chipcommon.o
diff --git a/drivers/ssb/bridge_pcmcia_80211.c b/drivers/ssb/bridge_pcmcia_80211.c
new file mode 100644
index 000000000000..d70568ea02d5
--- /dev/null
+++ b/drivers/ssb/bridge_pcmcia_80211.c
@@ -0,0 +1,128 @@
+/*
+ * Broadcom 43xx PCMCIA-SSB bridge module
+ *
+ * Copyright (c) 2007 Michael Buesch <m@bues.ch>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "ssb_private.h"
+
+static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
+
+static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb;
+ int err = -ENOMEM;
+ int res = 0;
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out_error;
+
+ err = -ENODEV;
+
+ dev->config_flags |= CONF_ENABLE_IRQ;
+
+ dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 |
+ WIN_USE_WAIT;
+ dev->resource[2]->start = 0;
+ dev->resource[2]->end = SSB_CORE_SIZE;
+ res = pcmcia_request_window(dev, dev->resource[2], 250);
+ if (res != 0)
+ goto err_kfree_ssb;
+
+ res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
+ if (res != 0)
+ goto err_disable;
+
+ if (!dev->irq)
+ goto err_disable;
+
+ res = pcmcia_enable_device(dev);
+ if (res != 0)
+ goto err_disable;
+
+ err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
+ if (err)
+ goto err_disable;
+ dev->priv = ssb;
+
+ return 0;
+
+err_disable:
+ pcmcia_disable_device(dev);
+err_kfree_ssb:
+ kfree(ssb);
+out_error:
+ ssb_err("Initialization failed (%d, %d)\n", res, err);
+ return err;
+}
+
+static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ ssb_bus_unregister(ssb);
+ pcmcia_disable_device(dev);
+ kfree(ssb);
+ dev->priv = NULL;
+}
+
+#ifdef CONFIG_PM
+static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ return ssb_bus_suspend(ssb);
+}
+
+static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ return ssb_bus_resume(ssb);
+}
+#else /* CONFIG_PM */
+# define ssb_host_pcmcia_suspend NULL
+# define ssb_host_pcmcia_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pcmcia_driver ssb_host_pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .name = "ssb-pcmcia",
+ .id_table = ssb_host_pcmcia_tbl,
+ .probe = ssb_host_pcmcia_probe,
+ .remove = ssb_host_pcmcia_remove,
+ .suspend = ssb_host_pcmcia_suspend,
+ .resume = ssb_host_pcmcia_resume,
+};
+
+/*
+ * These are not module init/exit functions!
+ * The module_pcmcia_driver() helper cannot be used here.
+ */
+int ssb_host_pcmcia_init(void)
+{
+ return pcmcia_register_driver(&ssb_host_pcmcia_driver);
+}
+
+void ssb_host_pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
+}
diff --git a/drivers/ssb/host_soc.c b/drivers/ssb/host_soc.c
new file mode 100644
index 000000000000..c809f255af34
--- /dev/null
+++ b/drivers/ssb/host_soc.c
@@ -0,0 +1,173 @@
+/*
+ * Sonics Silicon Backplane SoC host related functions.
+ * Subsystem core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readb(bus->mmio + offset);
+}
+
+static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readw(bus->mmio + offset);
+}
+
+static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readl(bus->mmio + offset);
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ struct ssb_bus *bus = dev->bus;
+ void __iomem *addr;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ addr = bus->mmio + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ u8 *buf = buffer;
+
+ while (count) {
+ *buf = __raw_readb(addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ __le16 *buf = buffer;
+
+ SSB_WARN_ON(count & 1);
+ while (count) {
+ *buf = (__force __le16)__raw_readw(addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ __le32 *buf = buffer;
+
+ SSB_WARN_ON(count & 3);
+ while (count) {
+ *buf = (__force __le32)__raw_readl(addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+#endif /* CONFIG_SSB_BLOCKIO */
+
+static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writeb(value, bus->mmio + offset);
+}
+
+static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writel(value, bus->mmio + offset);
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ struct ssb_bus *bus = dev->bus;
+ void __iomem *addr;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ addr = bus->mmio + offset;
+
+ switch (reg_width) {
+ case sizeof(u8): {
+ const u8 *buf = buffer;
+
+ while (count) {
+ __raw_writeb(*buf, addr);
+ buf++;
+ count--;
+ }
+ break;
+ }
+ case sizeof(u16): {
+ const __le16 *buf = buffer;
+
+ SSB_WARN_ON(count & 1);
+ while (count) {
+ __raw_writew((__force u16)(*buf), addr);
+ buf++;
+ count -= 2;
+ }
+ break;
+ }
+ case sizeof(u32): {
+ const __le32 *buf = buffer;
+
+ SSB_WARN_ON(count & 3);
+ while (count) {
+ __raw_writel((__force u32)(*buf), addr);
+ buf++;
+ count -= 4;
+ }
+ break;
+ }
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+#endif /* CONFIG_SSB_BLOCKIO */
+
+/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+const struct ssb_bus_ops ssb_host_soc_ops = {
+ .read8 = ssb_host_soc_read8,
+ .read16 = ssb_host_soc_read16,
+ .read32 = ssb_host_soc_read32,
+ .write8 = ssb_host_soc_write8,
+ .write16 = ssb_host_soc_write16,
+ .write32 = ssb_host_soc_write32,
+#ifdef CONFIG_SSB_BLOCKIO
+ .block_read = ssb_host_soc_block_read,
+ .block_write = ssb_host_soc_block_write,
+#endif
+};
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 8cf23a2468ba..5d1e9a0fc389 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -596,166 +596,6 @@ error:
return err;
}
-static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readb(bus->mmio + offset);
-}
-
-static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readw(bus->mmio + offset);
-}
-
-static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- return readl(bus->mmio + offset);
-}
-
-#ifdef CONFIG_SSB_BLOCKIO
-static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer,
- size_t count, u16 offset, u8 reg_width)
-{
- struct ssb_bus *bus = dev->bus;
- void __iomem *addr;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- addr = bus->mmio + offset;
-
- switch (reg_width) {
- case sizeof(u8): {
- u8 *buf = buffer;
-
- while (count) {
- *buf = __raw_readb(addr);
- buf++;
- count--;
- }
- break;
- }
- case sizeof(u16): {
- __le16 *buf = buffer;
-
- SSB_WARN_ON(count & 1);
- while (count) {
- *buf = (__force __le16)__raw_readw(addr);
- buf++;
- count -= 2;
- }
- break;
- }
- case sizeof(u32): {
- __le32 *buf = buffer;
-
- SSB_WARN_ON(count & 3);
- while (count) {
- *buf = (__force __le32)__raw_readl(addr);
- buf++;
- count -= 4;
- }
- break;
- }
- default:
- SSB_WARN_ON(1);
- }
-}
-#endif /* CONFIG_SSB_BLOCKIO */
-
-static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writeb(value, bus->mmio + offset);
-}
-
-static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writew(value, bus->mmio + offset);
-}
-
-static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
-{
- struct ssb_bus *bus = dev->bus;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- writel(value, bus->mmio + offset);
-}
-
-#ifdef CONFIG_SSB_BLOCKIO
-static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer,
- size_t count, u16 offset, u8 reg_width)
-{
- struct ssb_bus *bus = dev->bus;
- void __iomem *addr;
-
- offset += dev->core_index * SSB_CORE_SIZE;
- addr = bus->mmio + offset;
-
- switch (reg_width) {
- case sizeof(u8): {
- const u8 *buf = buffer;
-
- while (count) {
- __raw_writeb(*buf, addr);
- buf++;
- count--;
- }
- break;
- }
- case sizeof(u16): {
- const __le16 *buf = buffer;
-
- SSB_WARN_ON(count & 1);
- while (count) {
- __raw_writew((__force u16)(*buf), addr);
- buf++;
- count -= 2;
- }
- break;
- }
- case sizeof(u32): {
- const __le32 *buf = buffer;
-
- SSB_WARN_ON(count & 3);
- while (count) {
- __raw_writel((__force u32)(*buf), addr);
- buf++;
- count -= 4;
- }
- break;
- }
- default:
- SSB_WARN_ON(1);
- }
-}
-#endif /* CONFIG_SSB_BLOCKIO */
-
-/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
-static const struct ssb_bus_ops ssb_ssb_ops = {
- .read8 = ssb_ssb_read8,
- .read16 = ssb_ssb_read16,
- .read32 = ssb_ssb_read32,
- .write8 = ssb_ssb_write8,
- .write16 = ssb_ssb_write16,
- .write32 = ssb_ssb_write32,
-#ifdef CONFIG_SSB_BLOCKIO
- .block_read = ssb_ssb_block_read,
- .block_write = ssb_ssb_block_write,
-#endif
-};
-
static int ssb_fetch_invariants(struct ssb_bus *bus,
ssb_invariants_func_t get_invariants)
{
@@ -897,7 +737,6 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
return err;
}
-EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
#endif /* CONFIG_SSB_PCMCIAHOST */
#ifdef CONFIG_SSB_SDIOHOST
@@ -922,13 +761,14 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
EXPORT_SYMBOL(ssb_bus_sdiobus_register);
#endif /* CONFIG_SSB_PCMCIAHOST */
+#ifdef CONFIG_SSB_HOST_SOC
int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
ssb_invariants_func_t get_invariants)
{
int err;
bus->bustype = SSB_BUSTYPE_SSB;
- bus->ops = &ssb_ssb_ops;
+ bus->ops = &ssb_host_soc_ops;
err = ssb_bus_register(bus, get_invariants, baseaddr);
if (!err) {
@@ -938,6 +778,7 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
return err;
}
+#endif
int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
{
@@ -1464,6 +1305,12 @@ static int __init ssb_modinit(void)
/* don't fail SSB init because of this */
err = 0;
}
+ err = ssb_host_pcmcia_init();
+ if (err) {
+ ssb_err("PCMCIA host initialization failed\n");
+ /* don't fail SSB init because of this */
+ err = 0;
+ }
err = ssb_gige_init();
if (err) {
ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
@@ -1481,6 +1328,7 @@ fs_initcall(ssb_modinit);
static void __exit ssb_modexit(void)
{
ssb_gige_exit();
+ ssb_host_pcmcia_exit();
b43_pci_ssb_bridge_exit();
bus_unregister(&ssb_bustype);
}
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index 8a2ebc88c66f..15bfd5c7d2d7 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -94,6 +94,8 @@ extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus);
extern void ssb_pcmcia_exit(struct ssb_bus *bus);
extern int ssb_pcmcia_init(struct ssb_bus *bus);
+extern int ssb_host_pcmcia_init(void);
+extern void ssb_host_pcmcia_exit(void);
extern const struct ssb_bus_ops ssb_pcmcia_ops;
#else /* CONFIG_SSB_PCMCIAHOST */
static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
@@ -117,6 +119,13 @@ static inline int ssb_pcmcia_init(struct ssb_bus *bus)
{
return 0;
}
+static inline int ssb_host_pcmcia_init(void)
+{
+ return 0;
+}
+static inline void ssb_host_pcmcia_exit(void)
+{
+}
#endif /* CONFIG_SSB_PCMCIAHOST */
/* sdio.c */
@@ -148,6 +157,13 @@ static inline int ssb_sdio_init(struct ssb_bus *bus)
}
#endif /* CONFIG_SSB_SDIOHOST */
+/**************************************************
+ * host_soc.c
+ **************************************************/
+
+#ifdef CONFIG_SSB_HOST_SOC
+extern const struct ssb_bus_ops ssb_host_soc_ops;
+#endif
/* scan.c */
extern const char *ssb_core_name(u16 coreid);