* 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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQEcBAABAgAGBQJWMnbHAAoJEG4XJFUm622bGmMH/3MuH5mMdhT79Y1ySM9e+/1m
 6NHaRLK7Ibk1PHRUWpJqflZG5dc3arxjit5DciUZjInzjMWGWjNEYY6zFeT/fWw3
 dc+EZiFRsKIhYGTXi3a2uuRlEpxfx8Rvz2o6gh/kq4uQxrbdMVyKjgV+PF5HsUbp
 PDNV3L+ZeMZcGbDR3IFyBZHoH6yHZ9k49J/+OOXq+Z9lUGTeM135ZwaYNleORb/o
 dKcHlW0MY0lK32rD+XJI/2L8E8ne/TUe8fQQQH3XdyFS+4523HtY9ogLzk41Jfsj
 qzKhybzRnRXox+ZpjSNceENpE7XjhXIOshbjZMa3ZChDGwKCOSNA4BLyb314kMo=
 =YlL0
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
David S. Miller 2015-10-30 20:38:24 +09:00
commit a493bcf8d6
63 changed files with 1844 additions and 890 deletions

View File

@ -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

View File

@ -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;

View File

@ -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) +

View File

@ -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=======================*/

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 |=

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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_ */

View File

@ -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)

View File

@ -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;

View File

@ -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",

View File

@ -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, ...);

View File

@ -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",

View File

@ -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;

View File

@ -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,
};

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}

View File

@ -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));
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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,
};
@ -239,6 +242,19 @@ struct iwl_fw_error_dump_rb {
u8 data[];
};
/**
* 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

View File

@ -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__

View File

@ -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,
};
/**

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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 */

View File

@ -1523,6 +1523,69 @@ struct iwl_dts_measurement_cmd {
__le32 flags;
} __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
*

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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) {
cmd->rx_data_timeout =
cpu_to_le32(IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT);
cmd->tx_data_timeout =
cpu_to_le32(IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT);
} else {
if (!host_awake) {
cmd->rx_data_timeout =
cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
cmd->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_DEFAULT_PS_RX_DATA_TIMEOUT);
cmd->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

View File

@ -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 =

View File

@ -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];
if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {
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)) {
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

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

173
drivers/ssb/host_soc.c Normal file
View File

@ -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
};

View File

@ -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);
}

View File

@ -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);