On Thu, Nov 3, 2011 at 7:25 PM, Zefir Kurtisi <zefir.kurtisi@xxxxxxxxxxx> wrote: > This initial DFS module provides basic functionality to deal with > radar pulses reported by the DFS HW pattern detector. > > The reported data is evaluated and basic plausibility checks are > performed to filter false pulses. Passing radar pulses are > forwarded to pattern detectors (not part of this patch). > > The patch also includes > * new debug level ATH_DBG_DFS > * debugfs DFS radar statistics > > Signed-off-by: Zefir Kurtisi <zefir.kurtisi@xxxxxxxxxxx> > --- > drivers/net/wireless/ath/ath.h | 2 + > drivers/net/wireless/ath/ath9k/dfs.c | 192 ++++++++++++++++++++++++++++ > drivers/net/wireless/ath/ath9k/dfs.h | 24 ++++ > drivers/net/wireless/ath/ath9k/dfs_debug.c | 89 +++++++++++++ > drivers/net/wireless/ath/ath9k/dfs_debug.h | 59 +++++++++ > 5 files changed, 366 insertions(+), 0 deletions(-) > create mode 100644 drivers/net/wireless/ath/ath9k/dfs.c > create mode 100644 drivers/net/wireless/ath/ath9k/dfs.h > create mode 100644 drivers/net/wireless/ath/ath9k/dfs_debug.c > create mode 100644 drivers/net/wireless/ath/ath9k/dfs_debug.h > > diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h > index 46d6926..e38fcad 100644 > --- a/drivers/net/wireless/ath/ath.h > +++ b/drivers/net/wireless/ath/ath.h > @@ -215,6 +215,7 @@ do { \ > * @ATH_DBG_HWTIMER: hardware timer handling > * @ATH_DBG_BTCOEX: bluetooth coexistance > * @ATH_DBG_BSTUCK: stuck beacons > + * @ATH_DBG_DFS: radar datection > * @ATH_DBG_ANY: enable all debugging > * > * The debug level is used to control the amount and type of debugging output > @@ -240,6 +241,7 @@ enum ATH_DEBUG { > ATH_DBG_BTCOEX = 0x00002000, > ATH_DBG_WMI = 0x00004000, > ATH_DBG_BSTUCK = 0x00008000, > + ATH_DBG_DFS = 0x00010000, > ATH_DBG_ANY = 0xffffffff > }; > > diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c > new file mode 100644 > index 0000000..9d3c8b9 > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/dfs.c > @@ -0,0 +1,192 @@ > +/* > + * Copyright (c) 2008-2011 Atheros Communications Inc. > + * Copyright (c) 2011 Neratec Solutions AG > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include "hw.h" > +#include "hw-ops.h" > +#include "ath9k.h" > +#include "dfs.h" > +#include "dfs_debug.h" > + > +/* pulse duration reported is scaled with 1000/800 us */ > +#define AR93X_NSECS_PER_DUR 800 > +static u32 dur_to_usecs(u32 dur) > +{ > + return (dur * AR93X_NSECS_PER_DUR + 500) / 1000; > +} > + > +/* internal struct to pass radar data */ > +struct ath_radar_data { > + u8 pulse_bw_info; > + u8 rssi; > + u8 ext_rssi; > + u8 pulse_length_ext; > + u8 pulse_length_pri; > +}; > + > +/* TODO: move into or synchronize this with generic header > + * as soon as IF is defined */ > +struct dfs_radar_pulse { > + u16 freq; > + u64 ts; > + u32 width; > + u8 rssi; > +}; > + > +#define PRI_CH_RADAR_FOUND 0x01 > +#define EXT_CH_RADAR_FOUND 0x02 > +static bool postprocess_radar_event(struct ath_softc *sc, > + struct ath_radar_data *are, struct dfs_radar_pulse *drp) ath9k_postprocess_radar_event would be better? > +{ > + u8 rssi; > + u16 dur; > + > + ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_DFS, > + "pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n", > + are->pulse_bw_info, > + are->pulse_length_pri, are->rssi, > + are->pulse_length_ext, are->ext_rssi); > + > + /* Only the last 2 bits of the BW info are relevant, they indicate > + which channel the radar was detected in.*/ > + are->pulse_bw_info &= 0x03; > + > + switch (are->pulse_bw_info) { > + case 0: > + /* Bogus bandwidth info received in descriptor, > + so ignore this PHY error */ > + DFS_STAT_INC(sc, bwinfo_discards); > + return false; > + case PRI_CH_RADAR_FOUND: > + /* radar in ctrl channel */ > + dur = are->pulse_length_pri; > + DFS_STAT_INC(sc, pri_phy_errors); > + /* cannot use ctrl channel RSSI > + * if extension channel is stronger */ > + rssi = (are->ext_rssi >= (are->rssi + 3)) ? 0 : are->rssi; > + break; > + case EXT_CH_RADAR_FOUND: > + /* radar in extension channel */ > + dur = are->pulse_length_ext; > + DFS_STAT_INC(sc, ext_phy_errors); > + /* cannot use extension channel RSSI > + * if control channel is stronger */ > + rssi = (are->rssi >= (are->ext_rssi + 12)) ? 0 : are->ext_rssi; > + break; > + case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): > + /* > + * Conducted testing, when pulse is on DC, both pri and ext > + * durations are reported to be same > + * > + * Radiated testing, when pulse is on DC, different pri and > + * ext durations are reported, so take the larger of the two > + * */ > + if (are->pulse_length_ext >= are->pulse_length_pri) > + dur = are->pulse_length_ext; > + else > + dur = are->pulse_length_pri; > + DFS_STAT_INC(sc, dc_phy_errors); > + > + /* when both are present use stronger one */ > + rssi = (are->rssi < are->ext_rssi) ? are->ext_rssi : are->rssi; > + break; > + } > + > + if (rssi == 0) { > + DFS_STAT_INC(sc, rssi_discards); > + return false; > + } > + > + /* > + * TODO: check chirping pulses > + */ > + > + /* convert duration to usecs */ > + drp->width = dur_to_usecs(dur); > + drp->rssi = rssi; > + > + DFS_STAT_INC(sc, pulses_detected); > + return true; > +} > + > + > +/* > + * DFS: check PHY-error for radar pulse and feed the detector > + */ > +void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, > + struct ath_rx_status *rs, u64 mactime) > +{ > + struct ath_radar_data ard; > + u16 datalen; > + char *vdata_end; > + struct dfs_radar_pulse drp; > + struct ath_hw *ah = sc->sc_ah; > + struct ath_common *common = ath9k_hw_common(ah); > + > + if ((!(rs->rs_phyerr != ATH9K_PHYERR_RADAR)) && > + (!(rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT))) { > + ath_dbg(common, ATH_DBG_DFS, > + "Error: rs_phyer=0x%x not a radar error\n", > + rs->rs_phyerr); > + return; > + } > + > + datalen = rs->rs_datalen; > + if (datalen == 0) { > + DFS_STAT_INC(sc, datalen_discards); > + return; > + } > + > + ard.rssi = rs->rs_rssi_ctl0; > + ard.ext_rssi = rs->rs_rssi_ext0; > + > + /* hardware stores this as 8 bit signed value. > + * we will cap it at 0 if it is a negative number > + */ > + if (ard.rssi & 0x80) > + ard.rssi = 0; > + if (ard.ext_rssi & 0x80) > + ard.ext_rssi = 0; > + > + vdata_end = (char *)data + datalen; > + ard.pulse_bw_info = vdata_end[-1]; > + ard.pulse_length_ext = vdata_end[-2]; > + ard.pulse_length_pri = vdata_end[-3]; > + > + ath_dbg(common, ATH_DBG_DFS, > + "bw_info=%d, length_pri=%d, length_ext=%d, " > + "rssi_pri=%d, rssi_ext=%d\n", > + ard.pulse_bw_info, ard.pulse_length_pri, ard.pulse_length_ext, > + ard.rssi, ard.ext_rssi); > + > + drp.freq = ah->curchan->channel; > + drp.ts = mactime; > + if (postprocess_radar_event(sc, &ard, &drp)) { > + static u64 last_ts; > + ath_dbg(common, ATH_DBG_DFS, > + "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " > + "width=%d, rssi=%d, delta_ts=%llu\n", > + drp.freq, drp.ts, drp.width, drp.rssi, drp.ts-last_ts); > + last_ts = drp.ts; > + /* > + * TODO: forward pulse to pattern detector > + * > + * ieee80211_add_radar_pulse(drp.freq, drp.ts, > + * drp.width, drp.rssi); > + */ > + } > +} > +EXPORT_SYMBOL(ath9k_dfs_process_phyerr); > diff --git a/drivers/net/wireless/ath/ath9k/dfs.h b/drivers/net/wireless/ath/ath9k/dfs.h > new file mode 100644 > index 0000000..4d95cad > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/dfs.h > @@ -0,0 +1,24 @@ > +/* > + * Copyright (c) 2008-2011 Atheros Communications Inc. > + * Copyright (c) 2011 Neratec Solutions AG > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#ifndef ATH9K_DFS_H > +#define ATH9K_DFS_H > + > +void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, > + struct ath_rx_status *rs, u64 mactime); > + > +#endif /* ATH9K_DFS_H */ > diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c > new file mode 100644 > index 0000000..3c03552 > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c > @@ -0,0 +1,89 @@ > +/* > + * Copyright (c) 2008-2011 Atheros Communications Inc. > + * Copyright (c) 2011 Neratec Solutions AG > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > + > +#include <linux/debugfs.h> > + > +#include "ath9k.h" > +#include "dfs_debug.h" > + > + > +#if defined(CONFIG_ATH9K_DEBUGFS) > + > +#define ATH9K_DFS_STAT(s, p) \ > + len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ > + sc->debug.stats.dfs_stats.p); > + > +static ssize_t read_file_dfs(struct file *file, char __user *user_buf, > + size_t count, loff_t *ppos) > +{ > + struct ath_softc *sc = file->private_data; > + struct ath9k_hw_version *hw_ver = &sc->sc_ah->hw_version; > + char *buf; > + unsigned int len = 0, size = 8000; > + ssize_t retval = 0; > + > + buf = kzalloc(size, GFP_KERNEL); > + if (buf == NULL) > + return -ENOMEM; > + > + len += snprintf(buf + len, size - len, "DFS support for " > + "macVersion = 0x%x, macRev = 0x%x: %s\n", > + hw_ver->macVersion, hw_ver->macRev, > + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? > + "enabled" : "disabled"); > + ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected); > + ATH9K_DFS_STAT("Datalen discards ", datalen_discards); > + ATH9K_DFS_STAT("RSSI discards ", rssi_discards); > + ATH9K_DFS_STAT("BW info discards ", bwinfo_discards); > + ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors); > + ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors); > + ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors); > + > + if (len > size) > + len = size; > + > + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); > + kfree(buf); > + > + return retval; > +} > + > +static int ath9k_dfs_debugfs_open(struct inode *inode, struct file *file) > +{ > + file->private_data = inode->i_private; > + return 0; > +} > + > + > +static const struct file_operations fops_dfs_stats = { > + .read = read_file_dfs, > + .open = ath9k_dfs_debugfs_open, > + .owner = THIS_MODULE, > + .llseek = default_llseek, > +}; > + > + > +void ath9k_dfs_init_debug(struct ath_softc *sc) > +{ > + debugfs_create_file("dfs_stats", S_IRUSR, > + sc->debug.debugfs_phy, sc, &fops_dfs_stats); > +} > +EXPORT_SYMBOL(ath9k_dfs_init_debug); > + > +#endif /* CONFIG_ATH9K_DEBUGFS */ > + > diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h > new file mode 100644 > index 0000000..079cf53 > --- /dev/null > +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h > @@ -0,0 +1,59 @@ > +/* > + * Copyright (c) 2008-2011 Atheros Communications Inc. > + * Copyright (c) 2011 Neratec Solutions AG > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > + > +#ifndef DFS_DEBUG_H > +#define DFS_DEBUG_H > + > +#include "hw.h" > + > +/** > + * struct ath_dfs_stats - DFS Statistics > + * > + * @pulses_detected: No. of pulses detected so far > + * @datalen_discards: No. of pulses discarded due to invalid datalen > + * @rssi_discards: No. of pulses discarded due to invalid RSSI > + * @bwinfo_discards: No. of pulses discarded due to invalid BW info > + * @pri_phy_errors: No. of pulses reported for primary channel > + * @ext_phy_errors: No. of pulses reported for extension channel > + * @dc_phy_errors: No. of pulses reported for primary + extension channel > + */ > +struct ath_dfs_stats { > + u32 pulses_detected; > + u32 datalen_discards; > + u32 rssi_discards; > + u32 bwinfo_discards; > + u32 pri_phy_errors; > + u32 ext_phy_errors; > + u32 dc_phy_errors; > +}; > + > + > +#if defined(CONFIG_ATH9K_DEBUGFS) > + > +#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++) > +void ath9k_dfs_init_debug(struct ath_softc *sc); > + > +#else > + > +#define DFS_STAT_INC(sc, c) do { } while (0) > +static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } > + > +#endif > + > + > +#endif /* DFS_DEBUG_H */ > -- > 1.7.4.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-wireless" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- shafi -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html