Commit 56e1bd77 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-linville' of git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx

Conflicts:
	drivers/net/wireless/ti/wlcore/main.c
parents 9ebea382 5b37649b
menuconfig WL1251
tristate "TI wl1251 driver support"
depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS
depends on MAC80211 && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
......
wl12xx-objs = main.o cmd.o acx.o debugfs.o
wl12xx-objs = main.o cmd.o acx.o debugfs.o scan.o event.o
obj-$(CONFIG_WL12XX) += wl12xx.o
......@@ -284,3 +284,40 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
kfree(radio_parms);
return ret;
}
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch)
{
struct wl12xx_cmd_channel_switch *cmd;
int ret;
wl1271_debug(DEBUG_ACX, "cmd channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->role_id = wlvif->role_id;
cmd->channel = ch_switch->channel->hw_value;
cmd->switch_time = ch_switch->count;
cmd->stop_tx = ch_switch->block_tx;
/* FIXME: control from mac80211 in the future */
/* Enable TX on the target channel */
cmd->post_switch_tx_disable = 0;
ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send channel switch command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
......@@ -103,10 +103,30 @@ struct wl1271_ext_radio_parms_cmd {
u8 padding[3];
} __packed;
struct wl12xx_cmd_channel_switch {
struct wl1271_cmd_header header;
u8 role_id;
/* The new serving channel */
u8 channel;
/* Relative time of the serving channel switch in TBTT units */
u8 switch_time;
/* Stop the role TX, should expect it after radar detection */
u8 stop_tx;
/* The target channel tx status 1-stopped 0-open*/
u8 post_switch_tx_disable;
u8 padding[3];
} __packed;
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
#endif /* __WL12XX_CMD_H__ */
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "event.h"
#include "scan.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
bool *timeout)
{
u32 local_event;
switch (event) {
case WLCORE_EVENT_ROLE_STOP_COMPLETE:
local_event = ROLE_STOP_COMPLETE_EVENT_ID;
break;
case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
break;
default:
/* event not implemented */
return 0;
}
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
}
int wl12xx_process_mailbox_events(struct wl1271 *wl)
{
struct wl12xx_event_mailbox *mbox = wl->mbox;
u32 vector;
vector = le32_to_cpu(mbox->events_vector);
vector &= ~(le32_to_cpu(mbox->events_mask));
wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
if (wl->scan_wlvif)
wl12xx_scan_completed(wl, wl->scan_wlvif);
}
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
wl1271_debug(DEBUG_EVENT,
"PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
mbox->scheduled_scan_status);
wlcore_scan_sched_scan_results(wl);
}
if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
wlcore_event_sched_scan_completed(wl,
mbox->scheduled_scan_status);
if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
wlcore_event_soft_gemini_sense(wl,
mbox->soft_gemini_sense_info);
if (vector & BSS_LOSE_EVENT_ID)
wlcore_event_beacon_loss(wl, 0xff);
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
wlcore_event_ba_rx_constraint(wl,
BIT(mbox->role_id),
mbox->rx_ba_allowed);
if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
wlcore_event_channel_switch(wl, 0xff,
mbox->channel_switch_status);
if (vector & DUMMY_PACKET_EVENT_ID)
wlcore_event_dummy_packet(wl);
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if (vector & MAX_TX_RETRY_EVENT_ID)
wlcore_event_max_tx_failure(wl,
le16_to_cpu(mbox->sta_tx_retry_exceeded));
if (vector & INACTIVE_STA_EVENT_ID)
wlcore_event_inactive_sta(wl,
le16_to_cpu(mbox->sta_aging_status));
if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
wlcore_event_roc_complete(wl);
return 0;
}
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_EVENT_H__
#define __WL12XX_EVENT_H__
#include "../wlcore/wlcore.h"
enum {
MEASUREMENT_START_EVENT_ID = BIT(8),
MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
SCAN_COMPLETE_EVENT_ID = BIT(10),
WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
RESERVED1 = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
RADAR_DETECTED_EVENT_ID = BIT(16),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
DUMMY_PACKET_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
INACTIVE_STA_EVENT_ID = BIT(26),
PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
};
struct wl12xx_event_mailbox {
__le32 events_vector;
__le32 events_mask;
__le32 reserved_1;
__le32 reserved_2;
u8 number_of_scan_results;
u8 scan_tag;
u8 completed_scan_status;
u8 reserved_3;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
u8 change_auto_mode_timeout;
u8 scheduled_scan_status;
u8 reserved4;
/* tuned channel (roc) */
u8 roc_channel;
__le16 hlid_removed_bitmap;
/* bitmap of aged stations (by HLID) */
__le16 sta_aging_status;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le16 sta_tx_retry_exceeded;
/* discovery completed results */
u8 discovery_tag;
u8 number_of_preq_results;
u8 number_of_prsp_results;
u8 reserved_5;
/* rx ba constraint */
u8 role_id; /* 0xFF means any role. */
u8 rx_ba_allowed;
u8 reserved_6[2];
/* Channel switch results */
u8 channel_switch_role_id;
u8 channel_switch_status;
u8 reserved_7[2];
u8 ps_poll_delivery_failure_role_ids;
u8 stopped_role_ids;
u8 started_role_ids;
u8 reserved_8[9];
} __packed;
int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
bool *timeout);
int wl12xx_process_mailbox_events(struct wl1271 *wl);
#endif
This diff is collapsed.
This diff is collapsed.
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL12XX_SCAN_H__
#define __WL12XX_SCAN_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/cmd.h"
#include "../wlcore/scan.h"
#define WL12XX_MAX_CHANNELS_5GHZ 23
struct basic_scan_params {
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
u8 role_id;
/* Number of scan channels in the list (maximum 30) */
u8 n_ch;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 n_probe_reqs;
u8 tid_trigger;
u8 ssid_len;
u8 use_ssid_list;
/* Rate bit field for sending the probes */
__le32 tx_rate;
u8 ssid[IEEE80211_MAX_SSID_LEN];
/* Band to scan */
u8 band;
u8 scan_tag;
u8 padding2[2];
} __packed;
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
__le32 min_duration;
__le32 max_duration;
__le32 bssid_lsb;
__le16 bssid_msb;
u8 early_termination;
u8 tx_power_att;
u8 channel;
/* FW internal use only! */
u8 dfs_candidate;
u8 activity_detected;
u8 pad;
} __packed;
struct wl1271_cmd_scan {
struct wl1271_cmd_header header;
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
/* src mac address */
u8 addr[ETH_ALEN];
u8 padding[2];
} __packed;
struct wl1271_cmd_sched_scan_config {
struct wl1271_cmd_header header;
__le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
s8 rssi_threshold; /* for filtering (in dBm) */
s8 snr_threshold; /* for filtering (in dB) */
u8 cycles; /* maximum number of scan cycles */
u8 report_after; /* report when this number of results are received */
u8 terminate; /* stop scanning after reporting */
u8 tag;
u8 bss_type; /* for filtering */
u8 filter_type;
u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 n_probe_reqs; /* Number of probes requests per channel */
u8 passive[SCAN_MAX_BANDS];
u8 active[SCAN_MAX_BANDS];
u8 dfs;
u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
channels in BG band */
u8 role_id;
u8 padding[1];
struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
struct conn_scan_ch_params channels_5[WL12XX_MAX_CHANNELS_5GHZ];
struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
} __packed;
struct wl1271_cmd_sched_scan_start {
struct wl1271_cmd_header header;
u8 tag;
u8 role_id;
u8 padding[2];
} __packed;
struct wl1271_cmd_sched_scan_stop {
struct wl1271_cmd_header header;
u8 tag;
u8 role_id;
u8 padding[2];
} __packed;
int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_scan_request *req);
int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies);
void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
#endif
......@@ -24,19 +24,37 @@
#include "conf.h"
/* minimum FW required for driver for wl127x */
/* WiLink 6/7 chip IDs */
#define CHIP_ID_127X_PG10 (0x04030101)
#define CHIP_ID_127X_PG20 (0x04030111)
#define CHIP_ID_128X_PG10 (0x05030101)
#define CHIP_ID_128X_PG20 (0x05030111)
/* FW chip version for wl127x */
#define WL127X_CHIP_VER 6
#define WL127X_IFTYPE_VER 3
#define WL127X_MAJOR_VER 10
#define WL127X_SUBTYPE_VER 2
#define WL127X_MINOR_VER 115
/* minimum single-role FW version for wl127x */
#define WL127X_IFTYPE_SR_VER 3
#define WL127X_MAJOR_SR_VER 10
#define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_SR_VER 115
/* minimum multi-role FW version for wl127x */
#define WL127X_IFTYPE_MR_VER 5
#define WL127X_MAJOR_MR_VER 7
#define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_MR_VER 115
/* minimum FW required for driver for wl128x */
/* FW chip version for wl128x */
#define WL128X_CHIP_VER 7
#define WL128X_IFTYPE_VER 3
#define WL128X_MAJOR_VER 10
#define WL128X_SUBTYPE_VER 2
#define WL128X_MINOR_VER 115
/* minimum single-role FW version for wl128x */
#define WL128X_IFTYPE_SR_VER 3
#define WL128X_MAJOR_SR_VER 10
#define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL128X_MINOR_SR_VER 115
/* minimum multi-role FW version for wl128x */
#define WL128X_IFTYPE_MR_VER 5
#define WL128X_MAJOR_MR_VER 7
#define WL128X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
#define WL128X_MINOR_MR_VER 42
#define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
......@@ -55,6 +73,8 @@ struct wl12xx_priv {
int ref_clock;
int tcxo_clock;
struct wl127x_rx_mem_pool_addr *rx_mem_addr;
};
#endif /* __WL12XX_PRIV_H__ */
wl18xx-objs = main.o acx.o tx.o io.o debugfs.o
wl18xx-objs = main.o acx.o tx.o io.o debugfs.o scan.o cmd.o event.o
obj-$(CONFIG_WL18XX) += wl18xx.o
......@@ -75,7 +75,7 @@ int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("failed to set Tx checksum state: %d", ret);
goto out;
......@@ -109,3 +109,88 @@ int wl18xx_acx_clear_statistics(struct wl1271 *wl)
kfree(acx);
return ret;
}
int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
{
struct wlcore_peer_ht_operation_mode *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
hlid, wide);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
acx->hlid = hlid;
acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx peer ht operation mode failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
/*
* this command is basically the same as wl1271_acx_ht_capabilities,
* with the addition of supported rates. they should be unified in
* the next fw api change
*/
int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid)
{
struct wlcore_acx_peer_cap *acx;
int ret = 0;
u32 ht_capabilites = 0;
wl1271_debug(DEBUG_ACX,
"acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
ht_cap->ht_supported, ht_cap->cap, rate_set);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
if (allow_ht_operation && ht_cap->ht_supported) {
/* no need to translate capabilities - use the spec values */
ht_capabilites = ht_cap->cap;
/*
* this bit is not employed by the spec but only by FW to
* indicate peer HT support
*/
ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}
acx->hlid = hlid;
acx->ht_capabilites = cpu_to_le32(ht_capabilites);
acx->supported_rates = cpu_to_le32(rate_set);
ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ht capabilities setting failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
......@@ -26,7 +26,13 @@
#include "../wlcore/acx.h"
enum {
ACX_CLEAR_STATISTICS = 0x0047,
ACX_NS_IPV6_FILTER = 0x0050,
ACX_PEER_HT_OPERATION_MODE_CFG = 0x0051,
ACX_CSUM_CONFIG = 0x0052,
ACX_SIM_CONFIG = 0x0053,
ACX_CLEAR_STATISTICS = 0x0054,
ACX_AUTO_RX_STREAMING = 0x0055,
ACX_PEER_CAP = 0x0056
};
/* numbers of bits the length field takes (add 1 for the actual number) */
......@@ -278,10 +284,57 @@ struct wl18xx_acx_clear_statistics {
struct acx_header header;
};
enum wlcore_bandwidth {
WLCORE_BANDWIDTH_20MHZ,
WLCORE_BANDWIDTH_40MHZ,
};
struct wlcore_peer_ht_operation_mode {
struct acx_header header;
u8 hlid;
u8 bandwidth; /* enum wlcore_bandwidth */
u8 padding[2];
};
/*
* ACX_PEER_CAP
* this struct is very similar to wl1271_acx_ht_capabilities, with the
* addition of supported rates
*/
struct wlcore_acx_peer_cap {
struct acx_header header;
/* bitmask of capability bits supported by the peer */
__le32 ht_capabilites;
/* rates supported by the remote peer */
__le32 supported_rates;
/* Indicates to which link these capabilities apply. */
u8 hlid;
/*
* This the maximum A-MPDU length supported by the AP. The FW may not
* exceed this length when sending A-MPDUs
*/
u8 ampdu_max_length;
/* This is the minimal spacing required when sending A-MPDUs to the AP*/
u8 ampdu_min_spacing;
u8 padding;
} __packed;
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid);
#endif /* __WL18XX_ACX_H__ */
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
#include "../wlcore/hw_ops.h"
#include "cmd.h"
int wl18xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch)
{
struct wl18xx_cmd_channel_switch *cmd;
u32 supported_rates;
int ret;
wl1271_debug(DEBUG_ACX, "cmd channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->role_id = wlvif->role_id;
cmd->channel = ch_switch->channel->hw_value;
cmd->switch_time = ch_switch->count;
cmd->stop_tx = ch_switch->block_tx;
switch (ch_switch->channel->band) {
case IEEE80211_BAND_2GHZ:
cmd->band = WLCORE_BAND_2_4GHZ;
break;
case IEEE80211_BAND_5GHZ:
cmd->band = WLCORE_BAND_5GHZ;
break;
default:
wl1271_error("invalid channel switch band: %d",
ch_switch->channel->band);
ret = -EINVAL;
goto out_free;
}
supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
if (wlvif->p2p)
supported_rates &= ~CONF_TX_CCK_RATES;
cmd->local_supported_rates = cpu_to_le32(supported_rates);
cmd->channel_type = wlvif->channel_type;
ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send channel switch command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
/*
* This file is part of wl18xx
*
* Copyright (C) 2011 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_CMD_H__
#define __WL18XX_CMD_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/acx.h"
struct wl18xx_cmd_channel_switch {
struct wl1271_cmd_header header;
u8 role_id;
/* The new serving channel */
u8 channel;
/* Relative time of the serving channel switch in TBTT units */
u8 switch_time;
/* Stop the role TX, should expect it after radar detection */
u8 stop_tx;
__le32 local_supported_rates;
u8 channel_type;
u8 band;
u8 padding[2];
} __packed;
int wl18xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
#endif
......@@ -23,20 +23,21 @@
#define __WL18XX_CONF_H__
#define WL18XX_CONF_MAGIC 0x10e100ca
#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0003)
#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0005)
#define WL18XX_CONF_MASK 0x0000ffff
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
sizeof(struct wl18xx_priv_conf))
#define NUM_OF_CHANNELS_11_ABG 150
#define NUM_OF_CHANNELS_11_P 7
#define WL18XX_NUM_OF_SUB_BANDS 9
#define SRF_TABLE_LEN 16
#define PIN_MUXING_SIZE 2
#define WL18XX_TRACE_LOSS_GAPS_TX 10
#define WL18XX_TRACE_LOSS_GAPS_RX 18
struct wl18xx_mac_and_phy_params {
u8 phy_standalone;
u8 rdl;
u8 spare0;
u8 enable_clpc;
u8 enable_tx_low_pwr_on_siso_rdl;
u8 auto_detect;
......@@ -69,18 +70,26 @@ struct wl18xx_mac_and_phy_params {
u8 pwr_limit_reference_11_abg;
u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
u8 pwr_limit_reference_11p;
u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
u8 spare1[9];
u8 spare2[9];
u8 primary_clock_setting_time;
u8 clock_valid_on_wake_up;
u8 secondary_clock_setting_time;
u8 board_type;
/* enable point saturation */
u8 psat;
/* low/medium/high Tx power in dBm */
/* low/medium/high Tx power in dBm for STA-HP BG */
s8 low_power_val;
s8 med_power_val;
s8 high_power_val;
s8 per_sub_band_tx_trace_loss[WL18XX_TRACE_LOSS_GAPS_TX];
s8 per_sub_band_rx_trace_loss[WL18XX_TRACE_LOSS_GAPS_RX];
u8 tx_rf_margin;
/* low/medium/high Tx power in dBm for other role */
s8 low_power_val_2nd;
s8 med_power_val_2nd;
s8 high_power_val_2nd;
u8 padding[1];
} __packed;
......
/*
* This file is part of wl12xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "event.h"
#include "scan.h"
#include "../wlcore/cmd.h"
#include "../wlcore/debug.h"
int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
bool *timeout)
{
u32 local_event;
switch (event) {
case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
break;
case WLCORE_EVENT_DFS_CONFIG_COMPLETE:
local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
break;
default:
/* event not implemented */
return 0;
}
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
}
int wl18xx_process_mailbox_events(struct wl1271 *wl)
{
struct wl18xx_event_mailbox *mbox = wl->mbox;
u32 vector;
vector = le32_to_cpu(mbox->events_vector);
wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "scan results: %d",
mbox->number_of_scan_results);
if (wl->scan_wlvif)
wl18xx_scan_completed(wl, wl->scan_wlvif);
}
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
wl1271_debug(DEBUG_EVENT,
"PERIODIC_SCAN_REPORT_EVENT (results %d)",
mbox->number_of_sched_scan_results);
wlcore_scan_sched_scan_results(wl);
}
if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
wlcore_event_sched_scan_completed(wl, 1);
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
wlcore_event_ba_rx_constraint(wl,
le16_to_cpu(mbox->rx_ba_role_id_bitmap),
le16_to_cpu(mbox->rx_ba_allowed_bitmap));
if (vector & BSS_LOSS_EVENT_ID)
wlcore_event_beacon_loss(wl,
le16_to_cpu(mbox->bss_loss_bitmap));
if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
wlcore_event_channel_switch(wl,
le16_to_cpu(mbox->channel_switch_role_id_bitmap),
true);
if (vector & DUMMY_PACKET_EVENT_ID)
wlcore_event_dummy_packet(wl);
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if (vector & MAX_TX_FAILURE_EVENT_ID)
wlcore_event_max_tx_failure(wl,
le32_to_cpu(mbox->tx_retry_exceeded_bitmap));
if (vector & INACTIVE_STA_EVENT_ID)
wlcore_event_inactive_sta(wl,
le32_to_cpu(mbox->inactive_sta_bitmap));
if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
wlcore_event_roc_complete(wl);
return 0;
}
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_EVENT_H__
#define __WL18XX_EVENT_H__
#include "../wlcore/wlcore.h"
enum {
SCAN_COMPLETE_EVENT_ID = BIT(8),
RADAR_DETECTED_EVENT_ID = BIT(9),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(10),
BSS_LOSS_EVENT_ID = BIT(11),
MAX_TX_FAILURE_EVENT_ID = BIT(12),
DUMMY_PACKET_EVENT_ID = BIT(13),
INACTIVE_STA_EVENT_ID = BIT(14),
PEER_REMOVE_COMPLETE_EVENT_ID = BIT(15),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(16),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18),
DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20),
};
struct wl18xx_event_mailbox {
__le32 events_vector;
u8 number_of_scan_results;
u8 number_of_sched_scan_results;
__le16 channel_switch_role_id_bitmap;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
/* bitmap of removed links */
__le32 hlid_removed_bitmap;
/* rx ba constraint */
__le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */
__le16 rx_ba_allowed_bitmap;
/* bitmap of roc completed (by role id) */
__le16 roc_completed_bitmap;
/* bitmap of stations (by role id) with bss loss */
__le16 bss_loss_bitmap;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le32 tx_retry_exceeded_bitmap;
/* bitmap of inactive stations (by HLID) */
__le32 inactive_sta_bitmap;
} __packed;
int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
bool *timeout);
int wl18xx_process_mailbox_events(struct wl1271 *wl);
#endif
This diff is collapsed.
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/ieee80211.h>
#include "scan.h"
#include "../wlcore/debug.h"
static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
struct wlcore_scan_channels *cmd_channels)
{
memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
cmd->dfs = cmd_channels->dfs;
cmd->passive_active = cmd_channels->passive_active;
memcpy(cmd->channels_2, cmd_channels->channels_2,
sizeof(cmd->channels_2));
memcpy(cmd->channels_5, cmd_channels->channels_5,
sizeof(cmd->channels_2));
/* channels_4 are not supported, so no need to copy them */
}
static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_scan_request *req)
{
struct wl18xx_cmd_scan_params *cmd;
struct wlcore_scan_channels *cmd_channels = NULL;
int ret;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->role_id = wlvif->role_id;
if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL;
goto out;
}
cmd->scan_type = SCAN_TYPE_SEARCH;
cmd->rssi_threshold = -127;
cmd->snr_threshold = 0;
cmd->bss_type = SCAN_BSS_TYPE_ANY;
cmd->ssid_from_list = 0;
cmd->filter = 0;
cmd->add_broadcast = 0;
cmd->urgency = 0;
cmd->protect = 0;
cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->terminate_after = 0;
/* configure channels */
WARN_ON(req->n_ssids > 1);
cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
if (!cmd_channels) {
ret = -ENOMEM;
goto out;
}
wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
req->n_channels, req->n_ssids,
SCAN_TYPE_SEARCH);
wl18xx_adjust_channels(cmd, cmd_channels);
/*
* all the cycles params (except total cycles) should
* remain 0 for normal scan
*/
cmd->total_cycles = 1;
if (req->no_cck)
cmd->rate = WL18XX_SCAN_RATE_6;
cmd->tag = WL1271_SCAN_DEFAULT_TAG;
if (req->n_ssids) {
cmd->ssid_len = req->ssids[0].ssid_len;
memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
}
/* TODO: per-band ies? */
if (cmd->active[0]) {
u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
cmd->role_id, band,
req->ssids ? req->ssids[0].ssid : NULL,
req->ssids ? req->ssids[0].ssid_len : 0,
req->ie,
req->ie_len,
false);
if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed");
goto out;
}
}
if (cmd->active[1] || cmd->dfs) {
u8 band = IEEE80211_BAND_5GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
cmd->role_id, band,
req->ssids ? req->ssids[0].ssid : NULL,
req->ssids ? req->ssids[0].ssid_len : 0,
req->ie,
req->ie_len,
false);
if (ret < 0) {
wl1271_error("5GHz PROBE request template failed");
goto out;
}
}
wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
goto out;
}
out:
kfree(cmd_channels);
kfree(cmd);
return ret;
}
void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
wl->scan.failed = false;
cancel_delayed_work(&wl->scan_complete_work);
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
msecs_to_jiffies(0));
}
static
int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies)
{
struct wl18xx_cmd_scan_params *cmd;
struct wlcore_scan_channels *cmd_channels = NULL;
struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
int ret;
int filter_type;
wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
if (filter_type < 0)
return filter_type;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->role_id = wlvif->role_id;
if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
ret = -EINVAL;
goto out;
}
cmd->scan_type = SCAN_TYPE_PERIODIC;
cmd->rssi_threshold = c->rssi_threshold;
cmd->snr_threshold = c->snr_threshold;
/* don't filter on BSS type */
cmd->bss_type = SCAN_BSS_TYPE_ANY;
cmd->ssid_from_list = 1;
if (filter_type == SCAN_SSID_FILTER_LIST)
cmd->filter = 1;
cmd->add_broadcast = 0;
cmd->urgency = 0;
cmd->protect = 0;
cmd->n_probe_reqs = c->num_probe_reqs;
/* don't stop scanning automatically when something is found */
cmd->terminate_after = 0;
cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
if (!cmd_channels) {
ret = -ENOMEM;
goto out;
}
/* configure channels */
wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
req->n_channels, req->n_ssids,
SCAN_TYPE_PERIODIC);
wl18xx_adjust_channels(cmd, cmd_channels);
cmd->short_cycles_sec = 0;
cmd->long_cycles_sec = cpu_to_le16(req->interval);
cmd->short_cycles_count = 0;
cmd->total_cycles = 0;
cmd->tag = WL1271_SCAN_DEFAULT_TAG;
/* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
cmd->report_threshold = 1;
cmd->terminate_on_report = 0;
if (cmd->active[0]) {
u8 band = IEEE80211_BAND_2GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
cmd->role_id, band,
req->ssids ? req->ssids[0].ssid : NULL,
req->ssids ? req->ssids[0].ssid_len : 0,
ies->ie[band],
ies->len[band],
true);
if (ret < 0) {
wl1271_error("2.4GHz PROBE request template failed");
goto out;
}
}
if (cmd->active[1] || cmd->dfs) {
u8 band = IEEE80211_BAND_5GHZ;
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
cmd->role_id, band,
req->ssids ? req->ssids[0].ssid : NULL,
req->ssids ? req->ssids[0].ssid_len : 0,
ies->ie[band],
ies->len[band],
true);
if (ret < 0) {
wl1271_error("5GHz PROBE request template failed");
goto out;
}
}
wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("SCAN failed");
goto out;
}
out:
kfree(cmd_channels);
kfree(cmd);
return ret;
}
int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies)
{
return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
}
static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 scan_type)
{
struct wl18xx_cmd_scan_stop *stop;
int ret;
wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
stop = kzalloc(sizeof(*stop), GFP_KERNEL);
if (!stop) {
wl1271_error("failed to alloc memory to send sched scan stop");
return -ENOMEM;
}
stop->role_id = wlvif->role_id;
stop->scan_type = scan_type;
ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
if (ret < 0) {
wl1271_error("failed to send sched scan stop command");
goto out_free;
}
out_free:
kfree(stop);
return ret;
}
void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
__wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
}
int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_scan_request *req)
{
return wl18xx_scan_send(wl, wlvif, req);
}
int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
}
/*
* This file is part of wl18xx
*
* Copyright (C) 2012 Texas Instruments. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __WL18XX_SCAN_H__
#define __WL18XX_SCAN_H__
#include "../wlcore/wlcore.h"
#include "../wlcore/cmd.h"
#include "../wlcore/scan.h"
struct tracking_ch_params {
struct conn_scan_ch_params channel;
__le32 bssid_lsb;
__le16 bssid_msb;
u8 padding[2];
} __packed;
/* probe request rate */
enum
{
WL18XX_SCAN_RATE_1 = 0,
WL18XX_SCAN_RATE_5_5 = 1,
WL18XX_SCAN_RATE_6 = 2,
};
#define WL18XX_MAX_CHANNELS_5GHZ 32
struct wl18xx_cmd_scan_params {
struct wl1271_cmd_header header;
u8 role_id;
u8 scan_type;
s8 rssi_threshold; /* for filtering (in dBm) */
s8 snr_threshold; /* for filtering (in dB) */
u8 bss_type; /* for filtering */
u8 ssid_from_list; /* use ssid from configured ssid list */
u8 filter; /* forward only results with matching ssids */
/*
* add broadcast ssid in addition to the configured ssids.
* the driver should add dummy entry for it (?).
*/
u8 add_broadcast;
u8 urgency;
u8 protect; /* ??? */
u8 n_probe_reqs; /* Number of probes requests per channel */
u8 terminate_after; /* early terminate scan operation */
u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */
u8 dfs; /* number of dfs channels in 5ghz */
u8 passive_active; /* number of passive before active channels 2.4ghz */
__le16 short_cycles_sec;
__le16 long_cycles_sec;
u8 short_cycles_count;
u8 total_cycles; /* 0 - infinite */
u8 padding[2];
union {
struct {
struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
struct conn_scan_ch_params channels_5[WL18XX_MAX_CHANNELS_5GHZ];
struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
};
struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS];
} ;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
u8 tag;
u8 rate;
/* send SCAN_REPORT_EVENT in periodic scans after each cycle
* if number of results >= report_threshold. Must be 0 for
* non periodic scans
*/
u8 report_threshold;
/* Should periodic scan stop after a report event was created.
* Must be 0 for non periodic scans.
*/
u8 terminate_on_report;
u8 padding1[3];
} __packed;
struct wl18xx_cmd_scan_stop {
struct wl1271_cmd_header header;
u8 role_id;
u8 scan_type;
u8 padding[2];
} __packed;
int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_scan_request *req);
int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies);
void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
#endif
......@@ -28,6 +28,49 @@
#include "wl18xx.h"
#include "tx.h"
static
void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
struct ieee80211_tx_rate *rate)
{
u8 fw_rate = wl->fw_status_2->counters.tx_last_rate;
if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
wl1271_error("last Tx rate invalid: %d", fw_rate);
rate->idx = 0;
rate->flags = 0;
return;
}
if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) {
rate->idx = fw_rate;
rate->flags = 0;
} else {
rate->flags = IEEE80211_TX_RC_MCS;
rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0;
/* SGI modifier is counted as a separate rate */
if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI)
(rate->idx)--;
if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
(rate->idx)--;
/* this also covers the 40Mhz SGI case (= MCS15) */
if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI ||
fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) {
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
/* adjustment needed for range 0-7 */
rate->idx -= 8;
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
}
}
}
}
static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
{
struct ieee80211_tx_info *info;
......@@ -44,7 +87,6 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
/* a zero bit indicates Tx success */
tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
......@@ -56,11 +98,13 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
/* update the TX status info */
if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK;
/*
* first pass info->control.vif while it's valid, and then fill out
* the info->status structures
*/
wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]);
/* no real data about Tx completion */
info->status.rates[0].idx = -1;
info->status.rates[0].count = 0;
info->status.rates[0].flags = 0;
info->status.rates[0].count = 1; /* no data about retries */
info->status.ack_signal = -1;
if (!tx_success)
......
......@@ -26,10 +26,10 @@
/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
#define WL18XX_IFTYPE_VER 2
#define WL18XX_MAJOR_VER 0
#define WL18XX_SUBTYPE_VER 0
#define WL18XX_MINOR_VER 100
#define WL18XX_IFTYPE_VER 5
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
#define WL18XX_MINOR_VER 28
#define WL18XX_CMD_MAX_SIZE 740
......@@ -49,8 +49,8 @@ struct wl18xx_priv {
/* Index of last released Tx desc in FW */
u8 last_fw_rls_idx;
/* number of VIFs requiring extra spare mem-blocks */
int extra_spare_vif_count;
/* number of keys requiring extra spare mem-blocks */
int extra_spare_key_count;
};
#define WL18XX_FW_MAX_TX_STATUS_DESC 33
......@@ -68,7 +68,43 @@ struct wl18xx_fw_status_priv {
*/
u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
u8 padding[2];
/* A bitmap representing the currently suspended links. The suspend
* is short lived, for multi-channel Tx requirements.
*/
__le32 link_suspend_bitmap;
/* packet threshold for an "almost empty" AC,
* for Tx schedulng purposes
*/
u8 tx_ac_threshold;
/* number of packets to queue up for a link in PS */
u8 tx_ps_threshold;
/* number of packet to queue up for a suspended link */
u8 tx_suspend_threshold;
/* Should have less than this number of packets in queue of a slow
* link to qualify as high priority link
*/
u8 tx_slow_link_prio_threshold;
/* Should have less than this number of packets in queue of a fast
* link to qualify as high priority link
*/
u8 tx_fast_link_prio_threshold;
/* Should have less than this number of packets in queue of a slow
* link before we stop queuing up packets for it.
*/
u8 tx_slow_stop_threshold;
/* Should have less than this number of packets in queue of a fast
* link before we stop queuing up packets for it.
*/
u8 tx_fast_stop_threshold;
u8 padding[3];
};
#define WL18XX_PHY_VERSION_MAX_LEN 20
......
......@@ -1340,6 +1340,8 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
kfree(acx);
return ret;
}
EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities);
int wl1271_acx_set_ht_information(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
......@@ -1433,13 +1435,22 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
acx->win_size = wl->conf.ht.rx_ba_win_size;
acx->ssn = ssn;
ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
sizeof(*acx));
ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx,
sizeof(*acx),
BIT(CMD_STATUS_NO_RX_BA_SESSION));
if (ret < 0) {
wl1271_warning("acx ba receiver session failed: %d", ret);
goto out;
}
/* sometimes we can't start the session */
if (ret == CMD_STATUS_NO_RX_BA_SESSION) {
wl1271_warning("no fw rx ba on tid %d", tid_index);
ret = -EBUSY;
goto out;
}
ret = 0;
out:
kfree(acx);
return ret;
......
......@@ -1025,7 +1025,6 @@ enum {
ACX_CONFIG_HANGOVER = 0x0042,
ACX_FEATURE_CFG = 0x0043,
ACX_PROTECTION_CFG = 0x0044,
ACX_CHECKSUM_CONFIG = 0x0045,
};
......
......@@ -84,47 +84,57 @@ static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
static int wlcore_validate_fw_ver(struct wl1271 *wl)
{
unsigned int *fw_ver = wl->chip.fw_ver;
unsigned int *min_ver = wl->min_fw_ver;
unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_NORMAL) ?
wl->min_sr_fw_ver : wl->min_mr_fw_ver;
char min_fw_str[32] = "";
int i;
/* the chip must be exactly equal */
if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])
if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) &&
(min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]))
goto fail;
/* always check the next digit if all previous ones are equal */
if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE])
goto out;
else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE])
/* the firmware type must be equal */
if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) &&
(min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE]))
goto fail;
if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR])
goto out;
else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])
/* the project number must be equal */
if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) &&
(min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE]))
goto fail;
if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE])
goto out;
else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE])
/* the API version must be greater or equal */
if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) &&
(min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]))
goto fail;
if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR])
goto out;
else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])
/* if the API version is equal... */
if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) ||
(min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) &&
/* ...the minor must be greater or equal */
((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) &&
(min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])))
goto fail;
out:
return 0;
fail:
wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n"
"Please use at least FW %u.%u.%u.%u.%u.\n"
"You can get more information at:\n"
"http://wireless.kernel.org/en/users/Drivers/wl12xx",
for (i = 0; i < NUM_FW_VER; i++)
if (min_ver[i] == WLCORE_FW_VER_IGNORE)
snprintf(min_fw_str, sizeof(min_fw_str),
"%s*.", min_fw_str);
else
snprintf(min_fw_str, sizeof(min_fw_str),
"%s%u.", min_fw_str, min_ver[i]);
wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
"Please use at least FW %s\n"
"You can get the latest firmwares at:\n"
"git://github.com/TI-OpenLink/firmwares.git",
fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP],
min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR],
min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]);
fw_ver[FW_VER_MINOR], min_fw_str);
return -EINVAL;
}
......@@ -491,7 +501,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
if (ret < 0)
return ret;
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size;
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
......@@ -508,23 +518,6 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
*/
/* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID |
REGAINED_BSS_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
ROLE_STOP_COMPLETE_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
PERIODIC_SCAN_COMPLETE_EVENT_ID |
DUMMY_PACKET_EVENT_ID |
PEER_REMOVE_COMPLETE_EVENT_ID |
BA_SESSION_RX_CONSTRAINT_EVENT_ID |
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
INACTIVE_STA_EVENT_ID |
MAX_TX_RETRY_EVENT_ID |
CHANNEL_SWITCH_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
wl1271_error("EVENT mask setting failed");
......
This diff is collapsed.
......@@ -31,6 +31,8 @@ struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len, unsigned long valid_rets);
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
u8 *role_id);
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
......@@ -39,11 +41,14 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,
enum ieee80211_band band, int channel);
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
size_t len, unsigned long valid_rets);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 ps_mode, u16 auto_ps_timeout);
......@@ -75,22 +80,30 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id);
int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 hlid);
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
enum ieee80211_band band, u8 channel);
int wl12xx_croc(struct wl1271 *wl, u8 role_id);
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u8 hlid);
int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
enum ieee80211_band band);
int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 *hlid);
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
u32 mask, bool *timeout);
enum wl1271_commands {
CMD_INTERROGATE = 1, /* use this to read information elements */
......@@ -149,8 +162,11 @@ enum wl1271_commands {
CMD_WFD_START_DISCOVERY = 45,
CMD_WFD_STOP_DISCOVERY = 46,
CMD_WFD_ATTRIBUTE_CONFIG = 47,
CMD_NOP = 48,
CMD_LAST_COMMAND,
CMD_GENERIC_CFG = 48,
CMD_NOP = 49,
/* start of 18xx specific commands */
CMD_DFS_CHANNEL_CONFIG = 60,
MAX_COMMAND_ID = 0xFFFF,
};
......@@ -167,8 +183,8 @@ enum cmd_templ {
CMD_TEMPL_PS_POLL,
CMD_TEMPL_KLV,
CMD_TEMPL_DISCONNECT,
CMD_TEMPL_APP_PROBE_REQ_2_4,
CMD_TEMPL_APP_PROBE_REQ_5,
CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY,
CMD_TEMPL_APP_PROBE_REQ_5_LEGACY,
CMD_TEMPL_BAR, /* for firmware internal use only */
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
......@@ -179,6 +195,8 @@ enum cmd_templ {
CMD_TEMPL_DEAUTH_AP,
CMD_TEMPL_TEMPORARY,
CMD_TEMPL_LINK_MEASUREMENT_REPORT,
CMD_TEMPL_PROBE_REQ_2_4_PERIODIC,
CMD_TEMPL_PROBE_REQ_5_PERIODIC,
CMD_TEMPL_MAX = 0xff
};
......@@ -220,7 +238,8 @@ enum {
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
CMD_STATUS_TEMPLATE_OOM = 23,
CMD_STATUS_NO_RX_BA_SESSION = 24,
MAX_COMMAND_STATUS = 0xff
MAX_COMMAND_STATUS
};
#define CMDMBOX_HEADER_LEN 4
......@@ -345,7 +364,15 @@ struct wl12xx_cmd_role_start {
u8 reset_tsf;
u8 padding_1[4];
/*
* ap supports wmm (note that there is additional
* per-sta wmm configuration)
*/
u8 wmm;
u8 bcast_session_id;
u8 global_session_id;
u8 padding_1[1];
} __packed ap;
};
} __packed;
......@@ -515,7 +542,14 @@ struct wl12xx_cmd_set_peer_state {
u8 hlid;
u8 state;
u8 padding[2];
/*
* wmm is relevant for sta role only.
* ap role configures the per-sta wmm params in
* the add_peer command.
*/
u8 wmm;
u8 padding[1];
} __packed;
struct wl12xx_cmd_roc {
......@@ -558,7 +592,7 @@ struct wl12xx_cmd_add_peer {
u8 bss_index;
u8 sp_len;
u8 wmm;
u8 padding1;
u8 session_id;
} __packed;
struct wl12xx_cmd_remove_peer {
......@@ -597,6 +631,13 @@ enum wl12xx_fwlogger_output {
WL12XX_FWLOG_OUTPUT_HOST,
};
struct wl12xx_cmd_regdomain_dfs_config {
struct wl1271_cmd_header header;
__le32 ch_bit_map1;
__le32 ch_bit_map2;
} __packed;
struct wl12xx_cmd_config_fwlog {
struct wl1271_cmd_header header;
......@@ -626,27 +667,13 @@ struct wl12xx_cmd_stop_fwlog {
struct wl1271_cmd_header header;
} __packed;
struct wl12xx_cmd_channel_switch {
struct wl12xx_cmd_stop_channel_switch {
struct wl1271_cmd_header header;
u8 role_id;
/* The new serving channel */
u8 channel;
/* Relative time of the serving channel switch in TBTT units */
u8 switch_time;
/* Stop the role TX, should expect it after radar detection */
u8 stop_tx;
/* The target channel tx status 1-stopped 0-open*/
u8 post_switch_tx_disable;
u8 padding[3];
} __packed;
struct wl12xx_cmd_stop_channel_switch {
struct wl1271_cmd_header header;
} __packed;
/* Used to check radio status after calibration */
#define MAX_TLV_LENGTH 500
#define TEST_CMD_P2G_CAL 2 /* TX BiP */
......
......@@ -60,17 +60,46 @@ enum {
CONF_HW_RATE_INDEX_1MBPS = 0,
CONF_HW_RATE_INDEX_2MBPS = 1,
CONF_HW_RATE_INDEX_5_5MBPS = 2,
CONF_HW_RATE_INDEX_6MBPS = 3,
CONF_HW_RATE_INDEX_9MBPS = 4,
CONF_HW_RATE_INDEX_11MBPS = 5,
CONF_HW_RATE_INDEX_11MBPS = 3,
CONF_HW_RATE_INDEX_6MBPS = 4,
CONF_HW_RATE_INDEX_9MBPS = 5,
CONF_HW_RATE_INDEX_12MBPS = 6,
CONF_HW_RATE_INDEX_18MBPS = 7,
CONF_HW_RATE_INDEX_22MBPS = 8,
CONF_HW_RATE_INDEX_24MBPS = 9,
CONF_HW_RATE_INDEX_36MBPS = 10,
CONF_HW_RATE_INDEX_48MBPS = 11,
CONF_HW_RATE_INDEX_54MBPS = 12,
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
CONF_HW_RATE_INDEX_24MBPS = 8,
CONF_HW_RATE_INDEX_36MBPS = 9,
CONF_HW_RATE_INDEX_48MBPS = 10,
CONF_HW_RATE_INDEX_54MBPS = 11,
CONF_HW_RATE_INDEX_MCS0 = 12,
CONF_HW_RATE_INDEX_MCS1 = 13,
CONF_HW_RATE_INDEX_MCS2 = 14,
CONF_HW_RATE_INDEX_MCS3 = 15,
CONF_HW_RATE_INDEX_MCS4 = 16,
CONF_HW_RATE_INDEX_MCS5 = 17,
CONF_HW_RATE_INDEX_MCS6 = 18,
CONF_HW_RATE_INDEX_MCS7 = 19,
CONF_HW_RATE_INDEX_MCS7_SGI = 20,
CONF_HW_RATE_INDEX_MCS0_40MHZ = 21,
CONF_HW_RATE_INDEX_MCS1_40MHZ = 22,
CONF_HW_RATE_INDEX_MCS2_40MHZ = 23,
CONF_HW_RATE_INDEX_MCS3_40MHZ = 24,
CONF_HW_RATE_INDEX_MCS4_40MHZ = 25,
CONF_HW_RATE_INDEX_MCS5_40MHZ = 26,
CONF_HW_RATE_INDEX_MCS6_40MHZ = 27,
CONF_HW_RATE_INDEX_MCS7_40MHZ = 28,
CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI = 29,
/* MCS8+ rates overlap with 40Mhz rates */
CONF_HW_RATE_INDEX_MCS8 = 21,
CONF_HW_RATE_INDEX_MCS9 = 22,
CONF_HW_RATE_INDEX_MCS10 = 23,
CONF_HW_RATE_INDEX_MCS11 = 24,
CONF_HW_RATE_INDEX_MCS12 = 25,
CONF_HW_RATE_INDEX_MCS13 = 26,
CONF_HW_RATE_INDEX_MCS14 = 27,
CONF_HW_RATE_INDEX_MCS15 = 28,
CONF_HW_RATE_INDEX_MCS15_SGI = 29,
CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI,
};
#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
......@@ -415,11 +444,11 @@ struct conf_rx_settings {
#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS
/*
* Rates supported for data packets when operating as AP. Note the absence
* Rates supported for data packets when operating as STA/AP. Note the absence
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
* one. The rate dropped is not mandatory under any operating mode.
*/
#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
#define CONF_TX_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \
CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \
......@@ -677,6 +706,18 @@ struct conf_tx_settings {
/* Time in ms for Tx watchdog timer to expire */
u32 tx_watchdog_timeout;
/*
* when a slow link has this much packets pending, it becomes a low
* priority link, scheduling-wise
*/
u8 slow_link_thold;
/*
* when a fast link has this much packets pending, it becomes a low
* priority link, scheduling-wise
*/
u8 fast_link_thold;
} __packed;
enum {
......@@ -1047,6 +1088,7 @@ struct conf_roam_trigger_settings {
struct conf_scan_settings {
/*
* The minimum time to wait on each channel for active scans
* This value will be used whenever there's a connected interface.
*
* Range: u32 tu/1000
*/
......@@ -1054,24 +1096,37 @@ struct conf_scan_settings {
/*
* The maximum time to wait on each channel for active scans
* This value will be currently used whenever there's a
* connected interface. It shouldn't exceed 30000 (~30ms) to avoid
* possible interference of voip traffic going on while scanning.
*
* Range: u32 tu/1000
*/
u32 max_dwell_time_active;
/*
* The minimum time to wait on each channel for passive scans
/* The minimum time to wait on each channel for active scans
* when it's possible to have longer scan dwell times.
* Currently this is used whenever we're idle on all interfaces.
* Longer dwell times improve detection of networks within a
* single scan.
*
* Range: u32 tu/1000
*/
u32 min_dwell_time_passive;
u32 min_dwell_time_active_long;
/*
* The maximum time to wait on each channel for passive scans
/* The maximum time to wait on each channel for active scans
* when it's possible to have longer scan dwell times.
* See min_dwell_time_active_long
*
* Range: u32 tu/1000
*/
u32 max_dwell_time_passive;
u32 max_dwell_time_active_long;
/* time to wait on the channel for passive scans (in TU/1000) */
u32 dwell_time_passive;
/* time to wait on the channel for DFS scans (in TU/1000) */
u32 dwell_time_dfs;
/*
* Number of probe requests to transmit on each active scan channel
......@@ -1276,12 +1331,20 @@ struct conf_hangover_settings {
u8 window_size;
} __packed;
struct conf_recovery_settings {
/* BUG() on fw recovery */
u8 bug_on_recovery;
/* Prevent HW recovery. FW will remain stuck. */
u8 no_recovery;
} __packed;
/*
* The conf version consists of 4 bytes. The two MSB are the wlcore
* version, the two LSB are the lower driver's private conf
* version.
*/
#define WLCORE_CONF_VERSION (0x0002 << 16)
#define WLCORE_CONF_VERSION (0x0005 << 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
......@@ -1309,6 +1372,7 @@ struct wlcore_conf {
struct conf_fwlog fwlog;
struct conf_rate_policy_settings rate;
struct conf_hangover_settings hangover;
struct conf_recovery_settings recovery;
} __packed;
struct wlcore_conf_file {
......
......@@ -490,7 +490,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_HEX(chip.id);
DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
DRIVER_STATE_PRINT_INT(sched_scanning);
DRIVER_STATE_PRINT_INT(recovery_count);
#undef DRIVER_STATE_PRINT_INT
#undef DRIVER_STATE_PRINT_LONG
......@@ -560,7 +560,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
wlvif->bss_type == BSS_TYPE_IBSS) {
VIF_STATE_PRINT_INT(sta.hlid);
VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
......@@ -577,6 +576,10 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
}
VIF_STATE_PRINT_INT(last_tx_hlid);
VIF_STATE_PRINT_INT(tx_queue_count[0]);
VIF_STATE_PRINT_INT(tx_queue_count[1]);
VIF_STATE_PRINT_INT(tx_queue_count[2]);
VIF_STATE_PRINT_INT(tx_queue_count[3]);
VIF_STATE_PRINT_LHEX(links_map[0]);
VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
VIF_STATE_PRINT_INT(band);
......@@ -589,7 +592,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(beacon_int);
VIF_STATE_PRINT_INT(default_key);
VIF_STATE_PRINT_INT(aid);
VIF_STATE_PRINT_INT(session_counter);
VIF_STATE_PRINT_INT(psm_entry_retry);
VIF_STATE_PRINT_INT(power_level);
VIF_STATE_PRINT_INT(rssi_thold);
......@@ -993,7 +995,7 @@ static ssize_t sleep_auth_write(struct file *file,
return -EINVAL;
}
if (value < 0 || value > WL1271_PSM_MAX) {
if (value > WL1271_PSM_MAX) {
wl1271_warning("sleep_auth must be between 0 and %d",
WL1271_PSM_MAX);
return -ERANGE;
......
This diff is collapsed.
......@@ -46,33 +46,17 @@ enum {
RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5),
RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6),
RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7),
MEASUREMENT_START_EVENT_ID = BIT(8),
MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
SCAN_COMPLETE_EVENT_ID = BIT(10),
WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
RESERVED1 = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
RADAR_DETECTED_EVENT_ID = BIT(16),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
DUMMY_PACKET_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
INACTIVE_STA_EVENT_ID = BIT(26),
PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
};
/* events the driver might want to wait for */
enum wlcore_wait_event {
WLCORE_EVENT_ROLE_STOP_COMPLETE,
WLCORE_EVENT_PEER_REMOVE_COMPLETE,
WLCORE_EVENT_DFS_CONFIG_COMPLETE
};
enum {
EVENT_ENTER_POWER_SAVE_FAIL = 0,
EVENT_ENTER_POWER_SAVE_SUCCESS,
......@@ -80,61 +64,24 @@ enum {
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct event_mailbox {
__le32 events_vector;
__le32 events_mask;
__le32 reserved_1;
__le32 reserved_2;
u8 number_of_scan_results;
u8 scan_tag;
u8 completed_scan_status;
u8 reserved_3;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
u8 change_auto_mode_timeout;
u8 scheduled_scan_status;
u8 reserved4;
/* tuned channel (roc) */
u8 roc_channel;
__le16 hlid_removed_bitmap;
/* bitmap of aged stations (by HLID) */
__le16 sta_aging_status;
/* bitmap of stations (by HLID) which exceeded max tx retries */
__le16 sta_tx_retry_exceeded;
/* discovery completed results */
u8 discovery_tag;
u8 number_of_preq_results;
u8 number_of_prsp_results;
u8 reserved_5;
/* rx ba constraint */
u8 role_id; /* 0xFF means any role. */
u8 rx_ba_allowed;
u8 reserved_6[2];
/* Channel switch results */
u8 channel_switch_role_id;
u8 channel_switch_status;
u8 reserved_7[2];
u8 ps_poll_delivery_failure_role_ids;
u8 stopped_role_ids;
u8 started_role_ids;
u8 reserved_8[9];
} __packed;
struct wl1271;
int wl1271_event_unmask(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable);
void wlcore_event_sched_scan_completed(struct wl1271 *wl,
u8 status);
void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
unsigned long roles_bitmap,
unsigned long allowed_bitmap);
void wlcore_event_channel_switch(struct wl1271 *wl,
unsigned long roles_bitmap,
bool success);
void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap);
void wlcore_event_dummy_packet(struct wl1271 *wl);
void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap);
void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap);
void wlcore_event_roc_complete(struct wl1271 *wl);
void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr);
#endif
......@@ -201,4 +201,45 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
return buf_offset;
}
static inline void
wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u32 changed)
{
if (wl->ops->sta_rc_update)
wl->ops->sta_rc_update(wl, wlvif, sta, changed);
}
static inline int
wlcore_hw_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid)
{
if (wl->ops->set_peer_cap)
return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation,
rate_set, hlid);
return 0;
}
static inline bool
wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid,
struct wl1271_link *lnk)
{
if (!wl->ops->lnk_high_prio)
BUG_ON(1);
return wl->ops->lnk_high_prio(wl, hlid, lnk);
}
static inline bool
wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid,
struct wl1271_link *lnk)
{
if (!wl->ops->lnk_low_prio)
BUG_ON(1);
return wl->ops->lnk_low_prio(wl, hlid, lnk);
}
#endif
......@@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl)
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
wl->scan_templ_id_2_4, NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_CFG_PROBE_REQ_5,
wl->scan_templ_id_5,
NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
......@@ -56,14 +56,16 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_APP_PROBE_REQ_2_4, NULL,
wl->sched_scan_templ_id_2_4,
NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
CMD_TEMPL_APP_PROBE_REQ_5, NULL,
wl->sched_scan_templ_id_5,
NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
......@@ -463,7 +465,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
supported_rates = CONF_TX_OFDM_RATES;
else
supported_rates = CONF_TX_AP_ENABLED_RATES;
supported_rates = CONF_TX_ENABLED_RATES;
/* unconditionally enable HT rates */
supported_rates |= CONF_TX_MCS_RATES;
......@@ -575,9 +577,6 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
/* Configure for power according to debugfs */
if (sta_auth != WL1271_PSM_ILLEGAL)
ret = wl1271_acx_sleep_auth(wl, sta_auth);
/* Configure for power always on */
else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
/* Configure for ELP power saving */
else
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
......@@ -679,6 +678,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
ret = wlcore_cmd_regdomain_config_locked(wl);
if (ret < 0)
return ret;
/* Bluetooth WLAN coexistence */
ret = wl1271_init_pta(wl);
if (ret < 0)
......
......@@ -105,13 +105,13 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
{
int ret;
ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
ret = wlcore_raw_read(wl, addr, wl->buffer_32,
sizeof(*wl->buffer_32), false);
if (ret < 0)
return ret;
if (val)
*val = le32_to_cpu(wl->buffer_32);
*val = le32_to_cpu(*wl->buffer_32);
return 0;
}
......@@ -119,9 +119,9 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
u32 val)
{
wl->buffer_32 = cpu_to_le32(val);
return wlcore_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
*wl->buffer_32 = cpu_to_le32(val);
return wlcore_raw_write(wl, addr, wl->buffer_32,
sizeof(*wl->buffer_32), false);
}
static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
......
This diff is collapsed.
......@@ -151,9 +151,6 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl12xx_queue_recovery_work(wl);
ret = -ETIMEDOUT;
goto err;
} else if (ret < 0) {
wl1271_error("ELP wakeup completion error.");
goto err;
}
}
......@@ -242,11 +239,12 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
struct ieee80211_tx_info *info;
unsigned long flags;
int filtered[NUM_TX_QUEUES];
struct wl1271_link *lnk = &wl->links[hlid];
/* filter all frames currently in the low level queues for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
filtered[i]++;
if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
......@@ -260,8 +258,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
}
spin_lock_irqsave(&wl->wl_lock, flags);
for (i = 0; i < NUM_TX_QUEUES; i++)
for (i = 0; i < NUM_TX_QUEUES; i++) {
wl->tx_queue_count[i] -= filtered[i];
if (lnk->wlvif)
lnk->wlvif->tx_queue_count[i] -= filtered[i];
}
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl);
......
......@@ -92,11 +92,16 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) {
status->flag |= RX_FLAG_MMIC_ERROR;
wl1271_warning("Michael MIC error");
wl1271_warning("Michael MIC error. Desc: 0x%x",
desc_err_code);
}
}
if (beacon)
wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
status->band);
}
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
......@@ -108,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
u8 reserved = 0;
u8 reserved = 0, offset_to_data = 0;
u16 seq_num;
u32 pkt_data_len;
......@@ -128,6 +133,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
reserved = RX_BUF_ALIGN;
else if (rx_align == WLCORE_RX_BUF_PADDED)
offset_to_data = RX_BUF_ALIGN;
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data;
......@@ -139,19 +146,15 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return 0;
}
switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
/* discard corrupted packets */
case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
case WL1271_RX_DESC_DECRYPT_FAIL:
wl1271_warning("corrupted packet in RX with status: 0x%x",
desc->status & WL1271_RX_DESC_STATUS_MASK);
return -EINVAL;
case WL1271_RX_DESC_SUCCESS:
case WL1271_RX_DESC_MIC_FAIL:
break;
default:
wl1271_error("invalid RX descriptor status: 0x%x",
desc->status & WL1271_RX_DESC_STATUS_MASK);
if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) {
hdr = (void *)(data + sizeof(*desc) + offset_to_data);
wl1271_warning("corrupted packet in RX: status: 0x%x len: %d",
desc->status & WL1271_RX_DESC_STATUS_MASK,
pkt_data_len);
wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc),
min(pkt_data_len,
ieee80211_hdrlen(hdr->frame_control)));
return -EINVAL;
}
......
......@@ -84,12 +84,11 @@
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
#define WL1271_RX_DESC_STATUS_MASK 0x03
#define WL1271_RX_DESC_STATUS_MASK 0x07
#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
#define WL1271_RX_DESC_MIC_FAIL 0x02
#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
#define RX_MEM_BLOCK_MASK 0xFF
#define RX_BUF_SIZE_MASK 0xFFF00
......
This diff is collapsed.
This diff is collapsed.
......@@ -326,8 +326,7 @@ static void wl1271_remove(struct sdio_func *func)
/* Undo decrement done above in wl1271_probe */
pm_runtime_get_noresume(&func->dev);
platform_device_del(glue->core);
platform_device_put(glue->core);
platform_device_unregister(glue->core);
kfree(glue);
}
......
......@@ -270,7 +270,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)];
struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
u32 *cmd;
......@@ -407,8 +407,7 @@ static int wl1271_remove(struct spi_device *spi)
{
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
platform_device_del(glue->core);
platform_device_put(glue->core);
platform_device_unregister(glue->core);
kfree(glue);
return 0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment