summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2016-01-06 13:18:01 +0100
committerBjørn Mork <bjorn@mork.no>2016-01-06 13:18:01 +0100
commitf988b02dad561cef24a68180a56eecf1700cfa36 (patch)
tree06165b980f70dd27b7f4244fbd26869afa05e28f
parentd5f375c39db18319f61d1f4f4b2d470750eed4c3 (diff)
parent99d3879cc72f2a25d44fb4bee96fd84eca028b04 (diff)
Merge remote-tracking branch 'origin/master' into bmork-current20160106bmork-current
-rwxr-xr-xbin/firmware/88W8897.binbin489084 -> 142024 bytes
-rw-r--r--debugfs.c128
-rw-r--r--dev.h15
-rw-r--r--fwcmd.c358
-rw-r--r--fwcmd.h14
-rw-r--r--hostcmd.h85
-rw-r--r--isr.c51
-rw-r--r--isr.h1
-rw-r--r--mac80211.c43
-rw-r--r--main.c36
-rw-r--r--rx.c6
-rw-r--r--test/README4
-rwxr-xr-xtest/hostapd.conf.dfs18
-rw-r--r--tx.c6
14 files changed, 714 insertions, 51 deletions
diff --git a/bin/firmware/88W8897.bin b/bin/firmware/88W8897.bin
index 10c5cb1..021a9ee 100755
--- a/bin/firmware/88W8897.bin
+++ b/bin/firmware/88W8897.bin
Binary files differ
diff --git a/debugfs.c b/debugfs.c
index 7638aa6..e2afa5e 100644
--- a/debugfs.c
+++ b/debugfs.c
@@ -262,6 +262,130 @@ static ssize_t mwl_debugfs_ampdu_read(struct file *file, char __user *ubuf,
return ret;
}
+static ssize_t mwl_debugfs_dfs_channel_read(struct file *file,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel*channel;
+ int i;
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ sband = priv->hw->wiphy->bands[NL80211_BAND_5GHZ];
+ if (!sband)
+ return -EINVAL;
+
+ p += sprintf(p, "\n");
+ for (i = 0; i < sband->n_channels; i++) {
+ channel = &sband->channels[i];
+ if (channel->flags & IEEE80211_CHAN_RADAR) {
+ p += sprintf(p, "%d(%d): flags: %08x dfs_state: %d\n",
+ channel->hw_value, channel->center_freq,
+ channel->flags, channel->dfs_state);
+ p += sprintf(p, "cac timer: %d ms\n", channel->dfs_cac_ms);
+ }
+ }
+ p += sprintf(p, "\n");
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
+ (unsigned long)p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_dfs_channel_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ struct ieee80211_supported_band *sband;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ int dfs_state = 0;
+ int cac_time = -1;
+ struct ieee80211_channel*channel;
+ int i;
+ ssize_t ret = count;
+
+ if (!buf)
+ return -ENOMEM;
+
+ sband = priv->hw->wiphy->bands[NL80211_BAND_5GHZ];
+ if (!sband) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ sscanf(buf, "%d %d", &dfs_state, &cac_time);
+
+ for (i = 0; i < sband->n_channels; i++) {
+ channel = &sband->channels[i];
+ if (channel->flags & IEEE80211_CHAN_RADAR) {
+ channel->dfs_state = dfs_state;
+ if (cac_time != -1)
+ channel->dfs_cac_ms = cac_time * 1000;
+ }
+ }
+
+done:
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t mwl_debugfs_dfs_radar_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+ ssize_t ret;
+
+ if (!p)
+ return -ENOMEM;
+
+ p += sprintf(p, "\n");
+ p += sprintf(p, "csa_active: %d\n", priv->csa_active);
+ p += sprintf(p, "dfs_region: %d\n", priv->dfs_region);
+ p += sprintf(p, "chirp_count_min: %d\n", priv->dfs_chirp_count_min);
+ p += sprintf(p, "chirp_time_interval: %d\n",
+ priv->dfs_chirp_time_interval);
+ p += sprintf(p, "pw_filter: %d\n", priv->dfs_pw_filter);
+ p += sprintf(p, "min_num_radar: %d\n", priv->dfs_min_num_radar);
+ p += sprintf(p, "min_pri_count: %d\n", priv->dfs_min_pri_count);
+ p += sprintf(p, "\n");
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
+ (unsigned long)p - page);
+ free_page(page);
+
+ return ret;
+}
+
+static ssize_t mwl_debugfs_dfs_radar_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
+
+ wiphy_info(priv->hw->wiphy, "simulate radar detected\n");
+ ieee80211_radar_detected(priv->hw);
+
+ return count;
+}
+
static int mwl_debugfs_reg_access(struct mwl_priv *priv, bool write)
{
struct ieee80211_hw *hw = priv->hw;
@@ -393,6 +517,8 @@ MWLWIFI_DEBUGFS_FILE_READ_OPS(info);
MWLWIFI_DEBUGFS_FILE_READ_OPS(vif);
MWLWIFI_DEBUGFS_FILE_READ_OPS(sta);
MWLWIFI_DEBUGFS_FILE_READ_OPS(ampdu);
+MWLWIFI_DEBUGFS_FILE_OPS(dfs_channel);
+MWLWIFI_DEBUGFS_FILE_OPS(dfs_radar);
MWLWIFI_DEBUGFS_FILE_OPS(regrdwr);
void mwl_debugfs_init(struct ieee80211_hw *hw)
@@ -410,6 +536,8 @@ void mwl_debugfs_init(struct ieee80211_hw *hw)
MWLWIFI_DEBUGFS_ADD_FILE(vif);
MWLWIFI_DEBUGFS_ADD_FILE(sta);
MWLWIFI_DEBUGFS_ADD_FILE(ampdu);
+ MWLWIFI_DEBUGFS_ADD_FILE(dfs_channel);
+ MWLWIFI_DEBUGFS_ADD_FILE(dfs_radar);
MWLWIFI_DEBUGFS_ADD_FILE(regrdwr);
}
diff --git a/dev.h b/dev.h
index 0d46457..f97330f 100644
--- a/dev.h
+++ b/dev.h
@@ -27,7 +27,7 @@
#include <net/mac80211.h>
#define MWL_DRV_NAME KBUILD_MODNAME
-#define MWL_DRV_VERSION "10.3.0.15-20151208"
+#define MWL_DRV_VERSION "10.3.0.16-20160105"
/* Map to 0x80000000 (Bus control) on BAR0 */
#define MACREG_REG_H2A_INTERRUPT_EVENTS 0x00000C18 /* (From host to ARM) */
@@ -296,6 +296,7 @@ struct mwl_priv {
u8 cal_tbl[200];
struct pci_dev *pdev;
+ struct device *dev;
void __iomem *iobase0; /* MEM Base Address Register 0 */
void __iomem *iobase1; /* MEM Base Address Register 1 */
u32 next_bar_num;
@@ -364,6 +365,15 @@ struct mwl_priv {
} ____cacheline_aligned_in_smp;
struct work_struct watchdog_ba_handle;
+ bool csa_active;
+ struct work_struct chnl_switch_handle;
+ enum nl80211_dfs_regions dfs_region;
+ u16 dfs_chirp_count_min;
+ u16 dfs_chirp_time_interval;
+ u16 dfs_pw_filter;
+ u16 dfs_min_num_radar;
+ u16 dfs_min_pri_count;
+
bool mfg_mode;
#ifdef CONFIG_DEBUG_FS
@@ -377,6 +387,7 @@ struct mwl_priv {
struct beacon_info {
bool valid;
u16 cap_info;
+ u8 power_constraint;
u8 b_rate_set[SYSADPT_MAX_DATA_RATES_G];
u8 op_rate_set[SYSADPT_MAX_DATA_RATES_G];
u8 ie_list_ht[148];
@@ -386,6 +397,7 @@ struct beacon_info {
u8 *ie_rsn48_ptr;
u8 *ie_ht_ptr;
u8 *ie_vht_ptr;
+ u8 *ie_country_ptr;
#ifdef CONFIG_MAC80211_MESH
u8 *ie_meshid_ptr;
u8 *ie_meshcfg_ptr;
@@ -396,6 +408,7 @@ struct beacon_info {
u8 ie_rsn48_len;
u8 ie_ht_len;
u8 ie_vht_len;
+ u8 ie_country_len;
#ifdef CONFIG_MAC80211_MESH
u8 ie_meshid_len;
u8 ie_meshcfg_len;
diff --git a/fwcmd.c b/fwcmd.c
index e89f202..15bf20e 100644
--- a/fwcmd.c
+++ b/fwcmd.c
@@ -85,6 +85,7 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
{ HOSTCMD_CMD_SET_INFRA_MODE, "SetInfraMode" },
{ HOSTCMD_CMD_802_11_RTS_THSD, "80211RtsThreshold" },
{ HOSTCMD_CMD_SET_EDCA_PARAMS, "SetEDCAParams" },
+ { HOSTCMD_CMD_802_11H_DETECT_RADAR, "80211hDetectRadar" },
{ HOSTCMD_CMD_SET_WMM_MODE, "SetWMMMode" },
{ HOSTCMD_CMD_HT_GUARD_INTERVAL, "HtGuardInterval" },
{ HOSTCMD_CMD_SET_FIXED_RATE, "SetFixedRate" },
@@ -98,12 +99,18 @@ static char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
{ HOSTCMD_CMD_AP_BEACON, "SetApBeacon" },
{ HOSTCMD_CMD_SET_NEW_STN, "SetNewStation" },
{ HOSTCMD_CMD_SET_APMODE, "SetApMode" },
+ { HOSTCMD_CMD_SET_SWITCH_CHANNEL, "SetSwitchChannel" },
{ HOSTCMD_CMD_UPDATE_ENCRYPTION, "UpdateEncryption" },
{ HOSTCMD_CMD_BASTREAM, "BAStream" },
+ { HOSTCMD_CMD_SET_SPECTRUM_MGMT, "SetSpectrumMgmt" },
+ { HOSTCMD_CMD_SET_POWER_CONSTRAINT, "SetPowerConstraint" },
+ { HOSTCMD_CMD_SET_COUNTRY_CODE, "SetCountryCode" },
{ HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL, "SetOptimizationLevel"},
{ HOSTCMD_CMD_DWDS_ENABLE, "DwdsEnable" },
{ HOSTCMD_CMD_FW_FLUSH_TIMER, "FwFlushTimer" },
{ HOSTCMD_CMD_SET_CDD, "SetCDD" },
+ { HOSTCMD_CMD_GET_TEMP, "GetTemp" },
+ { HOSTCMD_CMD_QUIET_MODE, "QuietMode" },
};
max_entries = ARRAY_SIZE(cmds);
@@ -272,7 +279,7 @@ static int mwl_fwcmd_set_tx_powers(struct mwl_priv *priv, u16 txpow[],
return 0;
}
-static u8 mwl_fwcmd_get_80m_pri_chnl_offset(u8 channel)
+static u8 mwl_fwcmd_get_80m_pri_chnl(u8 channel)
{
u8 act_primary = ACT_PRIMARY_CHAN_0;
@@ -377,6 +384,7 @@ static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv,
beacon_info->ie_vht_ptr = &beacon_info->ie_list_vht[0];
beacon_info->cap_info = le16_to_cpu(mgmt->u.beacon.capab_info);
+ beacon_info->power_constraint = 0;
pos = (u8 *)mgmt->u.beacon.variable;
left = len - baselen;
@@ -396,6 +404,10 @@ static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv,
}
switch (id) {
+ case WLAN_EID_COUNTRY:
+ beacon_info->ie_country_len = (elen + 2);
+ beacon_info->ie_country_ptr = (pos - 2);
+ break;
case WLAN_EID_SUPP_RATES:
case WLAN_EID_EXT_SUPP_RATES:
{
@@ -435,6 +447,10 @@ static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv,
}
}
break;
+ case WLAN_EID_PWR_CONSTRAINT:
+ if (elen == 1)
+ beacon_info->power_constraint = *pos;
+ break;
case WLAN_EID_RSN:
beacon_info->ie_rsn48_len = (elen + 2);
beacon_info->ie_rsn48_ptr = (pos - 2);
@@ -517,9 +533,6 @@ static int mwl_fwcmd_set_ies(struct mwl_priv *priv, struct mwl_vif *mwl_vif)
struct beacon_info *beacon = &mwl_vif->beacon_info;
u16 ie_list_len_proprietary = 0;
- if (!beacon->valid)
- return -EINVAL;
-
if (beacon->ie_ht_len > sizeof(pcmd->ie_list_ht))
goto einval;
@@ -587,9 +600,6 @@ static int mwl_fwcmd_set_ap_beacon(struct mwl_priv *priv,
struct hostcmd_cmd_ap_beacon *pcmd;
struct ds_params *phy_ds_param_set;
- if (!mwl_vif->beacon_info.valid)
- return -EINVAL;
-
/* wmm structure of start command is defined less one byte,
* due to following field country is not used, add byte one
* to bypass the check.
@@ -660,6 +670,120 @@ ielenerr:
return -EINVAL;
}
+static int mwl_fwcmd_set_spectrum_mgmt(struct mwl_priv *priv, bool enable)
+{
+ struct hostcmd_cmd_set_spectrum_mgmt *pcmd;
+
+ pcmd = (struct hostcmd_cmd_set_spectrum_mgmt *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_SPECTRUM_MGMT);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->spectrum_mgmt = cpu_to_le32(enable);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_SPECTRUM_MGMT)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(priv->hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
+static int mwl_fwcmd_set_power_constraint(struct mwl_priv *priv,
+ u32 power_constraint)
+{
+ struct hostcmd_cmd_set_power_constraint *pcmd;
+
+ pcmd = (struct hostcmd_cmd_set_power_constraint *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_POWER_CONSTRAINT);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->power_constraint = cpu_to_le32(power_constraint);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_POWER_CONSTRAINT)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(priv->hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
+static int mwl_fwcmd_set_country_code(struct mwl_priv *priv,
+ struct mwl_vif *mwl_vif,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct hostcmd_cmd_set_country_code *pcmd;
+ struct beacon_info *b_inf = &mwl_vif->beacon_info;
+ u8 chnl_len;
+ bool a_band;
+ bool enable = false;
+
+ if (b_inf->ie_country_ptr) {
+ if (bss_conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
+ a_band = false;
+ else if (bss_conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
+ a_band = true;
+ else
+ return -EINVAL;
+
+ chnl_len = b_inf->ie_country_len - 5;
+ if (a_band) {
+ if (chnl_len > sizeof(pcmd->domain_info.domain_entry_a))
+ return -EINVAL;
+ } else {
+ if (chnl_len > sizeof(pcmd->domain_info.domain_entry_g))
+ return -EINVAL;
+ }
+
+ enable = true;
+ }
+
+ pcmd = (struct hostcmd_cmd_set_country_code *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_COUNTRY_CODE);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->action = cpu_to_le32(enable);
+ if (enable) {
+ memcpy(pcmd->domain_info.country_string,
+ b_inf->ie_country_ptr + 2, 3);
+ if (a_band) {
+ pcmd->domain_info.g_chnl_len = 0;
+ pcmd->domain_info.a_chnl_len = chnl_len;
+ memcpy(pcmd->domain_info.domain_entry_a,
+ b_inf->ie_country_ptr + 5, chnl_len);
+ } else {
+ pcmd->domain_info.a_chnl_len = 0;
+ pcmd->domain_info.g_chnl_len = chnl_len;
+ memcpy(pcmd->domain_info.domain_entry_g,
+ b_inf->ie_country_ptr + 5, chnl_len);
+ }
+ }
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_COUNTRY_CODE)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(priv->hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
static int mwl_fwcmd_encryption_set_cmd_info(struct hostcmd_cmd_set_key *cmd,
u8 *addr,
struct ieee80211_key_conf *key)
@@ -1255,7 +1379,7 @@ int mwl_fwcmd_set_rf_channel(struct ieee80211_hw *hw,
case NL80211_CHAN_WIDTH_80:
chnl_width = CH_80_MHZ_WIDTH;
act_primary =
- mwl_fwcmd_get_80m_pri_chnl_offset(pcmd->curr_chnl);
+ mwl_fwcmd_get_80m_pri_chnl(pcmd->curr_chnl);
break;
default:
mutex_unlock(&priv->fwcmd_mutex);
@@ -1406,6 +1530,50 @@ int mwl_fwcmd_set_edca_params(struct ieee80211_hw *hw, u8 index,
return 0;
}
+int mwl_fwcmd_set_radar_detect(struct ieee80211_hw *hw, u16 action)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_802_11h_detect_radar *pcmd;
+ u16 radar_type = RADAR_TYPE_CODE_0;
+ u8 channel = hw->conf.chandef.chan->hw_value;
+
+ pcmd = (struct hostcmd_cmd_802_11h_detect_radar *)&priv->pcmd_buf[0];
+
+ if (priv->dfs_region == NL80211_DFS_JP) {
+ if (channel >= 52 && channel <= 64)
+ radar_type = RADAR_TYPE_CODE_53;
+ else if (channel >= 100 && channel <= 140)
+ radar_type = RADAR_TYPE_CODE_56;
+ else
+ radar_type = RADAR_TYPE_CODE_0;
+ } else if (priv->dfs_region == NL80211_DFS_ETSI) {
+ radar_type = RADAR_TYPE_CODE_ETSI;
+ }
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11H_DETECT_RADAR);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->action = cpu_to_le16(action);
+ pcmd->radar_type_code = cpu_to_le16(radar_type);
+ pcmd->min_chirp_cnt = cpu_to_le16(priv->dfs_chirp_count_min);
+ pcmd->chirp_time_intvl = cpu_to_le16(priv->dfs_chirp_time_interval);
+ pcmd->pw_filter = cpu_to_le16(priv->dfs_pw_filter);
+ pcmd->min_num_radar = cpu_to_le16(priv->dfs_min_num_radar);
+ pcmd->pri_min_num = cpu_to_le16(priv->dfs_min_pri_count);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_802_11H_DETECT_RADAR)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
{
struct mwl_priv *priv = hw->priv;
@@ -1678,24 +1846,49 @@ int mwl_fwcmd_set_beacon(struct ieee80211_hw *hw,
{
struct mwl_priv *priv = hw->priv;
struct mwl_vif *mwl_vif;
+ struct beacon_info *b_inf;
+ int rc;
mwl_vif = mwl_dev_get_vif(vif);
+ b_inf = &mwl_vif->beacon_info;
mwl_fwcmd_parse_beacon(priv, mwl_vif, beacon, len);
+ if (!b_inf->valid)
+ goto err;
+
if (mwl_fwcmd_set_ies(priv, mwl_vif))
goto err;
if (mwl_fwcmd_set_ap_beacon(priv, mwl_vif, &vif->bss_conf))
goto err;
- mwl_vif->beacon_info.valid = false;
+ if (mwl_fwcmd_bss_start(hw, vif, true))
+ goto err;
+
+ if (b_inf->cap_info & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ rc = mwl_fwcmd_set_spectrum_mgmt(priv, true);
+ else
+ rc = mwl_fwcmd_set_spectrum_mgmt(priv, false);
+ if (rc)
+ goto err;
+
+ if (b_inf->power_constraint)
+ rc = mwl_fwcmd_set_power_constraint(priv,
+ b_inf->power_constraint);
+ if (rc)
+ goto err;
+
+ if (mwl_fwcmd_set_country_code(priv, mwl_vif, &vif->bss_conf))
+ goto err;
+
+ b_inf->valid = false;
return 0;
err:
- mwl_vif->beacon_info.valid = false;
+ b_inf->valid = false;
return -EIO;
}
@@ -1755,13 +1948,19 @@ int mwl_fwcmd_set_new_stn_add(struct ieee80211_hw *hw,
pcmd->peer_info.vht_rx_channel_width = sta->bandwidth;
}
- /* Patch mesh interface for VHT based on 88W8897. Once if mac80211
+ /* Patch mesh interface for VHT based on chip type. Once if mac80211
* supports VHT for mesh interface, following code should be removed.
*/
if (vif->type == NL80211_IFTYPE_MESH_POINT) {
pcmd->peer_info.vht_max_rx_mcs = cpu_to_le32(0x0000fffa);
pcmd->peer_info.vht_cap = cpu_to_le32(0x33801931);
pcmd->peer_info.vht_rx_channel_width = 2;
+ if (priv->chip_type == MWL8864) {
+ if (priv->antenna_rx == ANTENNA_RX_4_AUTO) {
+ pcmd->peer_info.vht_max_rx_mcs =
+ cpu_to_le32(0x0000ffea);
+ }
+ }
}
pcmd->is_qos_sta = sta->wme;
@@ -1887,6 +2086,85 @@ int mwl_fwcmd_set_apmode(struct ieee80211_hw *hw, u8 apmode)
return 0;
}
+int mwl_fwcmd_set_switch_channel(struct mwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct hostcmd_cmd_set_switch_channel *pcmd;
+ struct cfg80211_chan_def *chandef = &ch_switch->chandef;
+ struct ieee80211_channel *channel = chandef->chan;
+ u32 chnl_flags, freq_band, chnl_width, act_primary, sec_chnl_offset;
+
+ if (priv->csa_active)
+ return 0;
+
+ if (channel->band == IEEE80211_BAND_2GHZ)
+ freq_band = FREQ_BAND_2DOT4GHZ;
+ else if (channel->band == IEEE80211_BAND_5GHZ)
+ freq_band = FREQ_BAND_5GHZ;
+ else
+ return -EINVAL;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ chnl_width = CH_20_MHZ_WIDTH;
+ act_primary = ACT_PRIMARY_CHAN_0;
+ sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ chnl_width = CH_40_MHZ_WIDTH;
+ if (chandef->center_freq1 > channel->center_freq) {
+ act_primary = ACT_PRIMARY_CHAN_0;
+ sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ } else {
+ act_primary = ACT_PRIMARY_CHAN_1;
+ sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ }
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ chnl_width = CH_80_MHZ_WIDTH;
+ act_primary =
+ mwl_fwcmd_get_80m_pri_chnl(channel->hw_value);
+ if ((act_primary == ACT_PRIMARY_CHAN_0) ||
+ (act_primary == ACT_PRIMARY_CHAN_2))
+ sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ chnl_flags = (freq_band & FREQ_BAND_MASK) |
+ ((chnl_width << CHNL_WIDTH_SHIFT) & CHNL_WIDTH_MASK) |
+ ((act_primary << ACT_PRIMARY_SHIFT) & ACT_PRIMARY_MASK);
+
+ pcmd = (struct hostcmd_cmd_set_switch_channel *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_SWITCH_CHANNEL);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->next_11h_chnl = cpu_to_le32(channel->hw_value);
+ pcmd->mode = cpu_to_le32(ch_switch->block_tx);
+ pcmd->init_count = cpu_to_le32(ch_switch->count + 1);
+ pcmd->chnl_flags = cpu_to_le32(chnl_flags);
+ pcmd->next_ht_extchnl_offset = cpu_to_le32(sec_chnl_offset);
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_SET_SWITCH_CHANNEL)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(priv->hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ priv->csa_active = true;
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
int mwl_fwcmd_update_encryption_enable(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u8 *addr, u8 encr_type)
@@ -2412,6 +2690,64 @@ int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw)
return 0;
}
+int mwl_fwcmd_get_temp(struct ieee80211_hw *hw, u32 *temp)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_get_temp *pcmd;
+
+ pcmd = (struct hostcmd_cmd_get_temp *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_TEMP);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_GET_TEMP)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ *temp = le32_to_cpu(pcmd->celcius);
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
+int mwl_fwcmd_quiet_mode(struct ieee80211_hw *hw, bool enable, u32 period,
+ u32 duration, u32 next_offset)
+{
+ struct mwl_priv *priv = hw->priv;
+ struct hostcmd_cmd_quiet_mode *pcmd;
+
+ pcmd = (struct hostcmd_cmd_quiet_mode *)&priv->pcmd_buf[0];
+
+ mutex_lock(&priv->fwcmd_mutex);
+
+ memset(pcmd, 0x00, sizeof(*pcmd));
+ pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_QUIET_MODE);
+ pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+ pcmd->action = cpu_to_le16(WL_SET);
+ pcmd->enable = cpu_to_le32(enable);
+ if (enable) {
+ pcmd->period = cpu_to_le32(period);
+ pcmd->duration = cpu_to_le32(duration);
+ pcmd->next_offset = cpu_to_le32(next_offset);
+ }
+
+ if (mwl_fwcmd_exec_cmd(priv, HOSTCMD_CMD_QUIET_MODE)) {
+ mutex_unlock(&priv->fwcmd_mutex);
+ wiphy_err(hw->wiphy, "failed execution\n");
+ return -EIO;
+ }
+
+ mutex_unlock(&priv->fwcmd_mutex);
+
+ return 0;
+}
+
int mwl_fwcmd_send_mfg_cmd(struct mwl_priv *priv, char *mfgcmd)
{
struct hostcmd_header *pcmd;
diff --git a/fwcmd.h b/fwcmd.h
index cc4b7d9..8b9809d 100644
--- a/fwcmd.h
+++ b/fwcmd.h
@@ -42,6 +42,10 @@
#define LINK_CS_STATE_AUTO 2
#define LINK_CS_STATE_AUTO_DISABLED 3
+#define STOP_DETECT_RADAR 0
+#define CAC_START 1
+#define MONITOR_START 3
+
enum {
WL_ANTENNATYPE_RX = 1,
WL_ANTENNATYPE_TX = 2,
@@ -104,6 +108,8 @@ int mwl_fwcmd_set_rts_threshold(struct ieee80211_hw *hw,
int mwl_fwcmd_set_edca_params(struct ieee80211_hw *hw, u8 index,
u16 cw_min, u16 cw_max, u8 aifs, u16 txop);
+int mwl_fwcmd_set_radar_detect(struct ieee80211_hw *hw, u16 action);
+
int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable);
int mwl_fwcmd_ht_guard_interval(struct ieee80211_hw *hw, u32 gi_type);
@@ -144,6 +150,9 @@ int mwl_fwcmd_set_new_stn_del(struct ieee80211_hw *hw,
int mwl_fwcmd_set_apmode(struct ieee80211_hw *hw, u8 apmode);
+int mwl_fwcmd_set_switch_channel(struct mwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch);
+
int mwl_fwcmd_update_encryption_enable(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u8 *addr, u8 encr_type);
@@ -193,6 +202,11 @@ int mwl_fwcmd_set_fw_flush_timer(struct ieee80211_hw *hw, u32 value);
int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw);
+int mwl_fwcmd_get_temp(struct ieee80211_hw *hw, u32 *temp);
+
+int mwl_fwcmd_quiet_mode(struct ieee80211_hw *hw, bool enable, u32 period,
+ u32 duration, u32 next_offset);
+
int mwl_fwcmd_send_mfg_cmd(struct mwl_priv *priv, char *mfgcmd);
#endif /* _FWCMD_H_ */
diff --git a/hostcmd.h b/hostcmd.h
index 37729b0..132a18a 100644
--- a/hostcmd.h
+++ b/hostcmd.h
@@ -34,6 +34,7 @@
#define HOSTCMD_CMD_SET_INFRA_MODE 0x010e /* per-vif */
#define HOSTCMD_CMD_802_11_RTS_THSD 0x0113
#define HOSTCMD_CMD_SET_EDCA_PARAMS 0x0115
+#define HOSTCMD_CMD_802_11H_DETECT_RADAR 0x0120
#define HOSTCMD_CMD_SET_WMM_MODE 0x0123
#define HOSTCMD_CMD_HT_GUARD_INTERVAL 0x0124
#define HOSTCMD_CMD_SET_FIXED_RATE 0x0126
@@ -47,12 +48,18 @@
#define HOSTCMD_CMD_AP_BEACON 0x1101 /* per-vif */
#define HOSTCMD_CMD_SET_NEW_STN 0x1111 /* per-vif */
#define HOSTCMD_CMD_SET_APMODE 0x1114
+#define HOSTCMD_CMD_SET_SWITCH_CHANNEL 0x1121
#define HOSTCMD_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */
#define HOSTCMD_CMD_BASTREAM 0x1125
+#define HOSTCMD_CMD_SET_SPECTRUM_MGMT 0x1128
+#define HOSTCMD_CMD_SET_POWER_CONSTRAINT 0x1129
+#define HOSTCMD_CMD_SET_COUNTRY_CODE 0x1130
#define HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL 0x1133
#define HOSTCMD_CMD_DWDS_ENABLE 0x1144
#define HOSTCMD_CMD_FW_FLUSH_TIMER 0x1148
#define HOSTCMD_CMD_SET_CDD 0x1150
+#define HOSTCMD_CMD_GET_TEMP 0x1159
+#define HOSTCMD_CMD_QUIET_MODE 0x1201
/* Define general result code for each command */
#define HOSTCMD_RESULT_OK 0x0000
@@ -356,6 +363,23 @@ struct hostcmd_cmd_set_edca_params {
u8 txq_num; /* Tx Queue number. */
} __packed;
+/* HOSTCMD_CMD_802_11H_DETECT_RADAR */
+#define RADAR_TYPE_CODE_0 0
+#define RADAR_TYPE_CODE_53 53
+#define RADAR_TYPE_CODE_56 56
+#define RADAR_TYPE_CODE_ETSI 151
+
+struct hostcmd_cmd_802_11h_detect_radar {
+ struct hostcmd_header cmd_hdr;
+ __le16 action;
+ __le16 radar_type_code;
+ __le16 min_chirp_cnt;
+ __le16 chirp_time_intvl;
+ __le16 pw_filter;
+ __le16 min_num_radar;
+ __le16 pri_min_num;
+} __packed;
+
/* HOSTCMD_CMD_SET_WMM_MODE */
struct hostcmd_cmd_set_wmm_mode {
struct hostcmd_header cmd_hdr;
@@ -613,6 +637,17 @@ struct hostcmd_cmd_set_apmode {
u8 apmode;
} __packed;
+/* HOSTCMD_CMD_SET_SWITCH_CHANNEL */
+struct hostcmd_cmd_set_switch_channel {
+ struct hostcmd_header cmd_hdr;
+ __le32 next_11h_chnl;
+ __le32 mode;
+ __le32 init_count;
+ __le32 chnl_flags;
+ __le32 next_ht_extchnl_offset;
+ __le32 dfs_test_mode;
+} __packed;
+
/* HOSTCMD_CMD_UPDATE_ENCRYPTION */
struct hostcmd_cmd_update_encryption {
struct hostcmd_header cmd_hdr;
@@ -760,6 +795,39 @@ struct hostcmd_cmd_bastream {
union ba_info ba_info;
} __packed;
+/* HOSTCMD_CMD_SET_SPECTRUM_MGMT */
+struct hostcmd_cmd_set_spectrum_mgmt {
+ struct hostcmd_header cmd_hdr;
+ __le32 spectrum_mgmt;
+} __packed;
+
+/* HOSTCMD_CMD_SET_POWER_CONSTRAINT */
+struct hostcmd_cmd_set_power_constraint {
+ struct hostcmd_header cmd_hdr;
+ __le32 power_constraint;
+} __packed;
+
+/* HOSTCMD_CMD_SET_COUNTRY_CODE */
+struct domain_chnl_entry {
+ u8 first_chnl_num;
+ u8 chnl_num;
+ u8 max_transmit_pw;
+} __packed;
+
+struct domain_country_info {
+ u8 country_string[3];
+ u8 g_chnl_len;
+ struct domain_chnl_entry domain_entry_g[1];
+ u8 a_chnl_len;
+ struct domain_chnl_entry domain_entry_a[20];
+} __packed;
+
+struct hostcmd_cmd_set_country_code {
+ struct hostcmd_header cmd_hdr;
+ __le32 action ; /* 0 -> unset, 1 ->set */
+ struct domain_country_info domain_info;
+} __packed;
+
/* HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL */
struct hostcmd_cmd_set_optimization_level {
struct hostcmd_header cmd_hdr;
@@ -785,4 +853,21 @@ struct hostcmd_cmd_set_cdd {
__le32 enable;
} __packed;
+/* HOSTCMD_CMD_GET_TEMP */
+struct hostcmd_cmd_get_temp {
+ struct hostcmd_header cmd_hdr;
+ __le32 celcius;
+ __le32 raw_data;
+} __packed;
+
+/* HOSTCMD_CMD_QUIET_MODE */
+struct hostcmd_cmd_quiet_mode {
+ struct hostcmd_header cmd_hdr;
+ __le16 action;
+ __le32 enable;
+ __le32 period;
+ __le32 duration;
+ __le32 next_offset;
+} __packed;
+
#endif /* _HOSTCMD_H_ */
diff --git a/isr.c b/isr.c
index 227b39d..02d93d4 100644
--- a/isr.c
+++ b/isr.c
@@ -66,6 +66,12 @@ irqreturn_t mwl_isr(int irq, void *dev_id)
}
}
+ if (int_status & MACREG_A2HRIC_BIT_RADAR_DETECT) {
+ int_status &= ~MACREG_A2HRIC_BIT_RADAR_DETECT;
+ wiphy_info(hw->wiphy, "radar detected by firmware\n");
+ ieee80211_radar_detected(hw);
+ }
+
if (int_status & MACREG_A2HRIC_BIT_QUE_EMPTY) {
int_status &= ~MACREG_A2HRIC_BIT_QUE_EMPTY;
@@ -84,11 +90,13 @@ irqreturn_t mwl_isr(int irq, void *dev_id)
}
}
+ if (int_status & MACREG_A2HRIC_BIT_CHAN_SWITCH) {
+ int_status &= ~MACREG_A2HRIC_BIT_CHAN_SWITCH;
+ ieee80211_queue_work(hw, &priv->chnl_switch_handle);
+ }
+
if (int_status & MACREG_A2HRIC_BA_WATCHDOG) {
status = readl(int_status_mask);
- writel((status & ~MACREG_A2HRIC_BA_WATCHDOG),
- int_status_mask);
- int_status &= ~MACREG_A2HRIC_BA_WATCHDOG;
ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
}
@@ -99,6 +107,34 @@ irqreturn_t mwl_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+void mwl_chnl_switch_event(struct work_struct *work)
+{
+ struct mwl_priv *priv =
+ container_of(work, struct mwl_priv, chnl_switch_handle);
+ struct mwl_vif *mwl_vif;
+ struct ieee80211_vif *vif;
+
+ if (!priv->csa_active) {
+ wiphy_err(priv->hw->wiphy,
+ "csa is not active (got channel switch event)\n");
+ return;
+ }
+
+ spin_lock_bh(&priv->vif_lock);
+ list_for_each_entry(mwl_vif, &priv->vif_list, list) {
+ vif = container_of((char *)mwl_vif, struct ieee80211_vif,
+ drv_priv[0]);
+
+ if (vif->csa_active)
+ ieee80211_csa_finish(vif);
+ }
+ spin_unlock_bh(&priv->vif_lock);
+
+ wiphy_info(priv->hw->wiphy, "channel switch is done\n");
+
+ priv->csa_active = false;
+}
+
void mwl_watchdog_ba_events(struct work_struct *work)
{
int rc;
@@ -106,12 +142,11 @@ void mwl_watchdog_ba_events(struct work_struct *work)
struct mwl_ampdu_stream *streams;
struct mwl_priv *priv =
container_of(work, struct mwl_priv, watchdog_ba_handle);
- u32 status;
rc = mwl_fwcmd_get_watchdog_bitmap(priv->hw, &bitmap);
if (rc)
- goto done;
+ return;
spin_lock_bh(&priv->stream_lock);
@@ -147,10 +182,4 @@ void mwl_watchdog_ba_events(struct work_struct *work)
}
spin_unlock_bh(&priv->stream_lock);
-
-done:
-
- status = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
- writel(status | MACREG_A2HRIC_BA_WATCHDOG,
- priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
}
diff --git a/isr.h b/isr.h
index 4c317e2..ec916b8 100644
--- a/isr.h
+++ b/isr.h
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
irqreturn_t mwl_isr(int irq, void *dev_id);
+void mwl_chnl_switch_event(struct work_struct *work);
void mwl_watchdog_ba_events(struct work_struct *work);
#endif /* _ISR_H_ */
diff --git a/mac80211.c b/mac80211.c
index 2eda307..75f813d 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -267,6 +267,12 @@ static int mwl_mac80211_config(struct ieee80211_hw *hw,
mwl_fwcmd_set_linkadapt_cs_mode(hw,
LINK_CS_STATE_AUTO);
rate = mwl_rates_50[0].hw_value;
+
+ if (conf->radar_enabled)
+ mwl_fwcmd_set_radar_detect(hw, MONITOR_START);
+ else
+ mwl_fwcmd_set_radar_detect(hw,
+ STOP_DETECT_RADAR);
}
rc = mwl_fwcmd_set_rf_channel(hw, conf);
@@ -335,19 +341,19 @@ static void mwl_mac80211_bss_info_changed_ap(struct ieee80211_hw *hw,
if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
struct sk_buff *skb;
- skb = ieee80211_beacon_get(hw, vif);
-
- if (skb) {
- mwl_fwcmd_set_beacon(hw, vif, skb->data, skb->len);
- dev_kfree_skb_any(skb);
- }
-
if ((info->ssid[0] != '\0') &&
(info->ssid_len != 0) &&
(!info->hidden_ssid))
mwl_fwcmd_broadcast_ssid_enable(hw, vif, true);
else
mwl_fwcmd_broadcast_ssid_enable(hw, vif, false);
+
+ skb = ieee80211_beacon_get(hw, vif);
+
+ if (skb) {
+ mwl_fwcmd_set_beacon(hw, vif, skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ }
}
if (changed & BSS_CHANGED_BEACON_ENABLED)
@@ -466,9 +472,9 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_MESH_POINT) {
sta_info->is_mesh_node = true;
- /* Patch mesh interface for HT based on 88W8897. When authsae or
- * wpa_supplicant is used for mesh security, HT capbility wan't
- * be set. This would be removed if problem is fixed.
+ /* Patch mesh interface for HT based on chip type. When authsae
+ * or wpa_supplicant is used for mesh security, HT capbility
+ * won't be set. This would be removed if problem is fixed.
*/
sta->ht_cap.ht_supported = true;
sta->ht_cap.cap = 0x6f;
@@ -476,6 +482,10 @@ static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
sta->ht_cap.mcs.rx_mask[1] = 0xff;
sta->ht_cap.ampdu_factor = 0x3;
sta->ht_cap.ampdu_density = 0x5;
+ if (priv->chip_type == MWL8864) {
+ if (priv->antenna_rx == ANTENNA_RX_4_AUTO)
+ sta->ht_cap.mcs.rx_mask[2] = 0xff;
+ }
}
if (sta->ht_cap.ht_supported) {
@@ -700,6 +710,18 @@ static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
return rc;
}
+static int mwl_mac80211_chnl_switch(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct mwl_priv *priv = hw->priv;
+ int rc = 0;
+
+ rc = mwl_fwcmd_set_switch_channel(priv, ch_switch);
+
+ return rc;
+}
+
const struct ieee80211_ops mwl_mac80211_ops = {
.tx = mwl_mac80211_tx,
.start = mwl_mac80211_start,
@@ -717,4 +739,5 @@ const struct ieee80211_ops mwl_mac80211_ops = {
.get_stats = mwl_mac80211_get_stats,
.get_survey = mwl_mac80211_get_survey,
.ampdu_action = mwl_mac80211_ampdu_action,
+ .pre_channel_switch = mwl_mac80211_chnl_switch,
};
diff --git a/main.c b/main.c
index 98af779..3fbd596 100644
--- a/main.c
+++ b/main.c
@@ -145,6 +145,10 @@ static const struct ieee80211_iface_combination ap_if_comb = {
.n_limits = ARRAY_SIZE(ap_if_limits),
.max_interfaces = SYSADPT_NUM_OF_AP,
.num_different_channels = 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80),
};
static int mwl_alloc_pci_resource(struct mwl_priv *priv)
@@ -156,7 +160,7 @@ static int mwl_alloc_pci_resource(struct mwl_priv *priv)
if (pci_resource_flags(pdev, 0) & 0x04)
priv->next_bar_num = 2; /* 64-bit */
- addr = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
+ addr = devm_ioremap_resource(priv->dev, &pdev->resource[0]);
if (IS_ERR(addr)) {
wiphy_err(priv->hw->wiphy,
"%s: cannot reserve PCI memory region 0\n",
@@ -166,7 +170,7 @@ static int mwl_alloc_pci_resource(struct mwl_priv *priv)
priv->iobase0 = addr;
wiphy_debug(priv->hw->wiphy, "priv->iobase0 = %p\n", priv->iobase0);
- addr = devm_ioremap_resource(&pdev->dev,
+ addr = devm_ioremap_resource(priv->dev,
&pdev->resource[priv->next_bar_num]);
if (IS_ERR(addr)) {
wiphy_err(priv->hw->wiphy,
@@ -178,7 +182,7 @@ static int mwl_alloc_pci_resource(struct mwl_priv *priv)
wiphy_debug(priv->hw->wiphy, "priv->iobase1 = %p\n", priv->iobase1);
priv->pcmd_buf =
- (unsigned short *)dmam_alloc_coherent(&priv->pdev->dev,
+ (unsigned short *)dmam_alloc_coherent(priv->dev,
CMD_BUF_SIZE,
&priv->pphys_cmd_buf,
GFP_KERNEL);
@@ -204,18 +208,15 @@ err:
static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name)
{
- struct pci_dev *pdev;
int rc = 0;
- pdev = priv->pdev;
-
#ifdef SUPPORT_MFG
if (priv->mfg_mode)
rc = mwl_mfg_request_firmware(priv);
else
#endif
rc = request_firmware((const struct firmware **)&priv->fw_ucode,
- fw_name, &priv->pdev->dev);
+ fw_name, priv->dev);
if (rc) {
if (priv->mfg_mode)
@@ -259,19 +260,23 @@ err_load_fw:
static void mwl_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
-#ifdef CONFIG_OF
struct ieee80211_hw *hw;
struct mwl_priv *priv;
+#ifdef CONFIG_OF
struct property *prop;
struct property *fcc_prop = NULL;
struct property *etsi_prop = NULL;
struct property *specific_prop = NULL;
u32 prop_value;
int i, j, k;
+#endif
hw = (struct ieee80211_hw *)wiphy_priv(wiphy);
priv = hw->priv;
+ priv->dfs_region = request->dfs_region;
+
+#ifdef CONFIG_OF
if (priv->pwr_node) {
for_each_property_of_node(priv->pwr_node, prop) {
if (strcmp(prop->name, "FCC") == 0)
@@ -288,7 +293,7 @@ static void mwl_reg_notifier(struct wiphy *wiphy,
if (specific_prop) {
prop = specific_prop;
} else {
- if (request->dfs_region == NL80211_DFS_ETSI)
+ if (priv->dfs_region == NL80211_DFS_ETSI)
prop = etsi_prop;
else
prop = fcc_prop;
@@ -548,6 +553,7 @@ static int mwl_wl_init(struct mwl_priv *priv)
#endif
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->vif_data_size = sizeof(struct mwl_vif);
hw->sta_data_size = sizeof(struct mwl_sta);
@@ -565,8 +571,16 @@ static int mwl_wl_init(struct mwl_priv *priv)
priv->powinited = 0;
+ priv->csa_active = false;
+ priv->dfs_chirp_count_min = 5;
+ priv->dfs_chirp_time_interval = 1000;
+ priv->dfs_pw_filter = 0;
+ priv->dfs_min_num_radar = 5;
+ priv->dfs_min_pri_count = 4;
+
/* Handle watchdog ba events */
INIT_WORK(&priv->watchdog_ba_handle, mwl_watchdog_ba_events);
+ INIT_WORK(&priv->chnl_switch_handle, mwl_chnl_switch_event);
tasklet_init(&priv->tx_task, (void *)mwl_tx_done, (unsigned long)hw);
tasklet_disable(&priv->tx_task);
@@ -750,18 +764,20 @@ static int mwl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* hook regulatory domain change notification */
hw->wiphy->reg_notifier = mwl_reg_notifier;
- SET_IEEE80211_DEV(hw, &pdev->dev);
pci_set_drvdata(pdev, hw);
priv = hw->priv;
priv->hw = hw;
priv->pdev = pdev;
+ priv->dev = &pdev->dev;
priv->chip_type = id->driver_data;
priv->disable_2g = false;
priv->disable_5g = false;
priv->antenna_tx = mwl_chip_tbl[priv->chip_type].antenna_tx;
priv->antenna_rx = mwl_chip_tbl[priv->chip_type].antenna_rx;
+ SET_IEEE80211_DEV(hw, priv->dev);
+
rc = mwl_alloc_pci_resource(priv);
if (rc)
goto err_alloc_pci_resource;
diff --git a/rx.c b/rx.c
index 49ae9f0..4bf2cb7 100644
--- a/rx.c
+++ b/rx.c
@@ -56,7 +56,7 @@ static int mwl_rx_ring_alloc(struct mwl_priv *priv)
desc = &priv->desc_data[0];
desc->prx_ring = (struct mwl_rx_desc *)
- dma_alloc_coherent(&priv->pdev->dev,
+ dma_alloc_coherent(priv->dev,
MAX_NUM_RX_RING_BYTES,
&desc->pphys_rx_ring,
GFP_KERNEL);
@@ -71,7 +71,7 @@ static int mwl_rx_ring_alloc(struct mwl_priv *priv)
desc->rx_hndl = kmalloc(MAX_NUM_RX_HNDL_BYTES, GFP_KERNEL);
if (!desc->rx_hndl) {
- dma_free_coherent(&priv->pdev->dev,
+ dma_free_coherent(priv->dev,
MAX_NUM_RX_RING_BYTES,
desc->prx_ring,
desc->pphys_rx_ring);
@@ -191,7 +191,7 @@ static void mwl_rx_ring_free(struct mwl_priv *priv)
if (desc->prx_ring) {
mwl_rx_ring_cleanup(priv);
- dma_free_coherent(&priv->pdev->dev,
+ dma_free_coherent(priv->dev,
MAX_NUM_RX_RING_BYTES,
desc->prx_ring,
desc->pphys_rx_ring);
diff --git a/test/README b/test/README
index a299f47..5766d98 100644
--- a/test/README
+++ b/test/README
@@ -1,7 +1,7 @@
1. Files for test:
- a. 88W8864.bin: F/W binary. Please put this file under directory '/lib/firmware/mwlwifi'.
- b. mwlwifi.ko: 88W8864 mac80211 driver kernel module.
+ a. 88W8864.bin,88W8897.bin: F/W binary. Please put this file under directory '/lib/firmware/mwlwifi'.
+ b. mwlwifi.ko: 88W8864/88W8897 mac80211 driver kernel module.
c. hostapd.conf: configuration file used to configure hostapd.
d. wpa_supplicant.conf: configuration file used to configure wpa_supplicant.
e. openwrt-mvebu-armada-xp-mamba-squashfs-factory.img: OpenWRT download image (built with kernel cfg80211/mac80211, iw, hostapd and wpa_supplicant).
diff --git a/test/hostapd.conf.dfs b/test/hostapd.conf.dfs
new file mode 100755
index 0000000..dc81e47
--- /dev/null
+++ b/test/hostapd.conf.dfs
@@ -0,0 +1,18 @@
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=mwlwifi_ap_test
+ignore_broadcast_ssid=0
+hw_mode=a
+channel=100
+auth_algs=1
+wmm_enabled=1
+ieee80211n=1
+ht_capab=[LDPC][HT40+][SHORT-GI-20][SHORT-GI-40]
+ieee80211ac=1
+vht_capab=[MAX-MPDU-7991][RXLDPC][SHORT-GI-80][RX-STBC-1][SU-BEAMFORMER][SU-BEAMFORMEE][MAX-A-MPDU-LEN-EXP7][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN]
+vht_oper_chwidth=1
+vht_oper_centr_freq_seg0_idx=106
+ieee80211d=1
+country_code=US
+ieee80211h=1
diff --git a/tx.c b/tx.c
index 75ccff7..6c1651b 100644
--- a/tx.c
+++ b/tx.c
@@ -76,7 +76,7 @@ static int mwl_tx_ring_alloc(struct mwl_priv *priv)
desc = &priv->desc_data[0];
- mem = dma_alloc_coherent(&priv->pdev->dev,
+ mem = dma_alloc_coherent(priv->dev,
MAX_NUM_TX_RING_BYTES *
SYSADPT_NUM_OF_DESC_DATA,
&desc->pphys_tx_ring,
@@ -106,7 +106,7 @@ static int mwl_tx_ring_alloc(struct mwl_priv *priv)
if (!mem) {
wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
- dma_free_coherent(&priv->pdev->dev,
+ dma_free_coherent(priv->dev,
MAX_NUM_TX_RING_BYTES *
SYSADPT_NUM_OF_DESC_DATA,
priv->desc_data[0].ptx_ring,
@@ -214,7 +214,7 @@ static void mwl_tx_ring_free(struct mwl_priv *priv)
int num;
if (priv->desc_data[0].ptx_ring) {
- dma_free_coherent(&priv->pdev->dev,
+ dma_free_coherent(priv->dev,
MAX_NUM_TX_RING_BYTES *
SYSADPT_NUM_OF_DESC_DATA,
priv->desc_data[0].ptx_ring,