From 99d3879cc72f2a25d44fb4bee96fd84eca028b04 Mon Sep 17 00:00:00 2001 From: David Lin Date: Wed, 6 Jan 2016 14:43:16 +0800 Subject: Commit mwlwifi driver 10.3.0.16-20160105. Added code to support DFS. Signed-off-by: David Lin --- bin/firmware/88W8897.bin | Bin 489084 -> 142024 bytes debugfs.c | 128 +++++++++++++++++ dev.h | 15 +- fwcmd.c | 358 +++++++++++++++++++++++++++++++++++++++++++++-- fwcmd.h | 14 ++ hostcmd.h | 85 +++++++++++ isr.c | 51 +++++-- isr.h | 1 + mac80211.c | 43 ++++-- main.c | 36 +++-- rx.c | 6 +- test/README | 4 +- test/hostapd.conf.dfs | 18 +++ tx.c | 6 +- 14 files changed, 714 insertions(+), 51 deletions(-) create mode 100755 test/hostapd.conf.dfs diff --git a/bin/firmware/88W8897.bin b/bin/firmware/88W8897.bin index 10c5cb1..021a9ee 100755 Binary files a/bin/firmware/88W8897.bin and b/bin/firmware/88W8897.bin 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 #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 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 8b985af..0845138 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, -- cgit v1.2.3