/* * Return the centre frequency for the current operating channel and * event. * * This is for post-Owl 11n chips which report pri/extension channel * events. */ static inline uint16_t dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc) { struct ieee80211com *ic; int chan_offset = 0, chan_width; /* Handle edge cases during startup/transition, shouldn't happen! */ if (dfs == NULL) return (0); if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) return (0); ic = dfs->ic; /* * * For wide channels, DC and ext frequencies need a bit of hand-holding * based on whether it's an upper or lower channel. */ chan_width = dfs_get_event_freqwidth(dfs); if (IEEE80211_IS_CHAN_11N_HT40PLUS(ic->ic_curchan)) chan_offset = chan_width; else if (IEEE80211_IS_CHAN_11N_HT40MINUS(ic->ic_curchan)) chan_offset = -chan_width; else chan_offset = 0; /* * Check for DC events first - the sowl code may just set all * the bits together.. */ if (is_dc) { /* * XXX TODO: Should DC events be considered 40MHz wide here? */ return (ieee80211_chan2freq(ic, ic->ic_curchan) + (chan_offset / 2)); } /* * For non-wide channels, the centre frequency is just ic_freq. * The centre frequency for pri events is still ic_freq. */ if (is_pri) { return (ieee80211_chan2freq(ic, ic->ic_curchan)); } if (is_ext) { return (ieee80211_chan2freq(ic, ic->ic_curchan) + chan_width); } /* XXX shouldn't get here */ return (ieee80211_chan2freq(ic, ic->ic_curchan)); }
/* Implement wmi_unified_vdev_start_cmd() here */ static int _ieee80211_resmgr_vap_start(ieee80211_resmgr_t resmgr, ieee80211_vap_t vap, struct ieee80211_channel *chan, u_int16_t reqid, u_int16_t max_start_time) { struct ieee80211com *ic = resmgr->ic; struct ol_ath_softc_net80211 *scn = OL_ATH_SOFTC_NET80211(ic); struct ol_ath_vap_net80211 *avn = OL_ATH_VAP_NET80211(vap); u_int32_t freq; bool disable_hw_ack= false; printk("OL vap_start +\n"); freq = ieee80211_chan2freq(resmgr->ic, chan); if (!freq) { printk("ERROR : INVALID Freq \n"); return 0; } #if ATH_SUPPORT_DFS if ( vap->iv_opmode == IEEE80211_M_HOSTAP && IEEE80211_IS_CHAN_DFS(chan)) { disable_hw_ack = true; } #endif /* BUG : Seen on AKronite, VDEV Start event response comes before setting * av_ol_resmgr_wait to TRUE, this make VAP not coming up issue. * Hence moving below assignment before sending VDEV_START_CMD_ID to target */ /* Interface is up, UMAC is waiting for * target response */ avn->av_ol_resmgr_wait = TRUE; spin_lock(&vap->init_lock); if (wmi_unified_vdev_start_send(scn->wmi_handle, avn->av_if_id, chan, freq, disable_hw_ack)) { printk("Unable to bring up the interface for ath_dev.\n"); spin_unlock(&vap->init_lock); return -1; } /* The channel configured in target is not same always with the vap desired channel due to 20/40 coexistence scenarios, so, channel is saved to configure on VDEV START RESP */ avn->av_ol_resmgr_chan = chan; vap->init_in_progress = true; spin_unlock(&vap->init_lock); printk("OL vap_start -\n"); return EBUSY; }
/* * Calculate the channel centre in MHz. */ static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs) { uint32_t chan_centre; uint32_t chan_width; int chan_offset; /* * For now, just handle up to VHT80 correctly. */ if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) { DFS_PRINTK("%s: dfs->ic=%p, that or curchan is null?\n", __func__, dfs->ic); return (0); /* * For now, the only 11ac channel with freq1/freq2 setup is * VHT80. * * XXX should have a flag macro to check this! */ } else if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) { /* 11AC, so cfreq1/cfreq2 are setup */ /* * XXX if it's 80+80 this won't work - need to use seg * appropriately! */ chan_centre = dfs->ic->ic_ieee2mhz( dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1, dfs->ic->ic_curchan->ic_flags); } else { /* HT20/HT40 */ /* * XXX this is hard-coded - it should be 5 or 10 for * half/quarter appropriately. */ chan_width = 20; /* Grab default channel centre */ chan_centre = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D */ if (IEEE80211_IS_CHAN_11N_HT40PLUS(dfs->ic->ic_curchan) || dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40PLUS) chan_offset = chan_width; else if (IEEE80211_IS_CHAN_11N_HT40MINUS(dfs->ic->ic_curchan) || dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40MINUS) chan_offset = -chan_width; else chan_offset = 0; /* Calculate new _real_ channel centre */ chan_centre += (chan_offset / 2); } /* * XXX half/quarter rate support! */ /* Return ev_chan_centre in MHz */ return (chan_centre); }
/* * Parse the radar summary frame. * * The frame contents _minus_ the TLV are passed in. */ static void radar_summary_parse(struct ath_dfs *dfs, const char *buf, size_t len, struct rx_radar_status *rsu) { uint32_t rs[2]; int freq_centre, freq; /* Drop out if we have < 2 DWORDs available */ if (len < sizeof(rs)) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | ATH_DEBUG_DFS_PHYERR_SUM, "%s: len (%zu) < expected (%zu)!", __func__, len, sizeof(rs)); } /* * Since the TLVs may be unaligned for some reason * we take a private copy into aligned memory. * This enables us to use the HAL-like accessor macros * into the DWORDs to access sub-DWORD fields. */ OS_MEMCPY(rs, buf, sizeof(rs)); DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR,"%s: two 32 bit values are: %08x %08x", __func__, rs[0], rs[1]); // DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s (p=%p):", __func__, buf); /* Populate the fields from the summary report */ rsu->tsf_offset = MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_TSF_OFFSET); rsu->pulse_duration = MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_DUR); rsu->is_chirp = MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_IS_CHIRP); rsu->sidx = sign_extend_32( MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_SIDX), 10); rsu->freq_offset = calc_freq_offset(rsu->sidx, PERE_IS_OVERSAMPLING(dfs)); /* These are only relevant if the pulse is a chirp */ rsu->delta_peak = sign_extend_32( MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_DELTA_PEAK), 6); rsu->delta_diff = MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_DELTA_DIFF); /* WAR for FCC Type 4*/ /* * HW is giving longer pulse duration (in case of VHT80, with traffic) * which fails to detect FCC type4 radar pulses. Added a work around to * fix the pulse duration and duration delta. * * IF VHT80 * && (primary_channel==30MHz || primary_channel== -30MHz) * && -4 <= pulse_index <= 4 * && !chirp * && pulse duration > 20 us * THEN * Set pulse duration to 20 us */ freq = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); freq_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; if ((IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan) && (abs(freq - freq_centre) == 30) && !rsu->is_chirp && abs(rsu->sidx) <= 4 && rsu->pulse_duration > 20)){ rsu->pulse_duration = 20; } }
/* * Find the channel information according to the scan entry */ int rtt_find_channel_info (void *arg, wlan_scan_entry_t scan_entry) { wmi_channel *wmi_chan; u_int32_t chan_mode; struct ieee80211com *ic; struct ieee80211_channel *se_chan; static const u_int modeflags[] = { 0, /* IEEE80211_MODE_AUTO */ MODE_11A, /* IEEE80211_MODE_11A */ MODE_11B, /* IEEE80211_MODE_11B */ MODE_11G, /* IEEE80211_MODE_11G */ 0, /* IEEE80211_MODE_FH */ 0, /* IEEE80211_MODE_TURBO_A */ 0, /* IEEE80211_MODE_TURBO_G */ MODE_11NA_HT20, /* IEEE80211_MODE_11NA_HT20 */ MODE_11NG_HT20, /* IEEE80211_MODE_11NG_HT20 */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40PLUS */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40MINUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40PLUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40MINUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40 */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40 */ MODE_11AC_VHT20, /* IEEE80211_MODE_11AC_VHT20 */ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40PLUS */ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40MINUS*/ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40 */ MODE_11AC_VHT80, /* IEEE80211_MODE_11AC_VHT80 */ }; adf_os_print("%s:\n", __func__); if (!(arg && scan_entry)) { return -1; //critical error } wmi_chan = ((channel_search *)arg)->channel; ic = ((channel_search *)arg)->ic; if(!(wmi_chan && ic)) { return -1; //critical error } se_chan = wlan_scan_entry_channel(scan_entry); if(!se_chan) { return -1; //critical error } wmi_chan->mhz = ieee80211_chan2freq(ic,se_chan); chan_mode = ieee80211_chan2mode(se_chan); WMI_SET_CHANNEL_MODE(wmi_chan, modeflags[chan_mode]); if(chan_mode == IEEE80211_MODE_11AC_VHT80) { if (se_chan->ic_ieee < 20) { wmi_chan->band_center_freq1 = ieee80211_ieee2mhz( se_chan->ic_vhtop_ch_freq_seg1, IEEE80211_CHAN_2GHZ); } else { wmi_chan->band_center_freq1 = ieee80211_ieee2mhz( se_chan->ic_vhtop_ch_freq_seg1, IEEE80211_CHAN_5GHZ); } } else if((chan_mode == IEEE80211_MODE_11NA_HT40PLUS) || (chan_mode == IEEE80211_MODE_11NG_HT40PLUS) || (chan_mode == IEEE80211_MODE_11AC_VHT40PLUS)) { wmi_chan->band_center_freq1 = wmi_chan->mhz + 10; } else if((chan_mode == IEEE80211_MODE_11NA_HT40MINUS) || (chan_mode == IEEE80211_MODE_11NG_HT40MINUS) || (chan_mode == IEEE80211_MODE_11AC_VHT40MINUS)) { wmi_chan->band_center_freq1 = wmi_chan->mhz - 10; } else { wmi_chan->band_center_freq1 = wmi_chan->mhz; } /* we do not support HT80PLUS80 yet */ wmi_chan->band_center_freq2=0; WMI_SET_CHANNEL_MIN_POWER(wmi_chan, se_chan->ic_minpower); WMI_SET_CHANNEL_MAX_POWER(wmi_chan, se_chan->ic_maxpower); WMI_SET_CHANNEL_REG_POWER(wmi_chan, se_chan->ic_maxregpower); WMI_SET_CHANNEL_ANTENNA_MAX(wmi_chan, se_chan->ic_antennamax); WMI_SET_CHANNEL_REG_CLASSID(wmi_chan, se_chan->ic_regClassId); if (IEEE80211_IS_CHAN_DFS(se_chan)) WMI_SET_CHANNEL_FLAG(wmi_chan, WMI_CHAN_FLAG_DFS); adf_os_print("WMI channel freq=%d, mode=%x band_center_freq1=%d\n", wmi_chan->mhz, WMI_GET_CHANNEL_MODE(wmi_chan), wmi_chan->band_center_freq1); return 1; //seccessful! }