diff options
author | adrian <adrian@FreeBSD.org> | 2014-03-29 19:53:04 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2014-03-29 19:53:04 +0000 |
commit | 8c08adf4bde0dcdda5489664a2e79bee8defe69c (patch) | |
tree | c27bd461c5b80af172a36d242fcbf4a33abfb3a0 | |
parent | 8d4e6b0a23d2356ec3c08c730ec6841a31d3c242 (diff) | |
download | FreeBSD-src-8c08adf4bde0dcdda5489664a2e79bee8defe69c.zip FreeBSD-src-8c08adf4bde0dcdda5489664a2e79bee8defe69c.tar.gz |
Add support to export the contents of the notification updates from the firmware.
Right now the NIC isn't actually exporting useful data. I'm not quite sure
why this is. :(
-rw-r--r-- | sys/dev/iwi/if_iwi.c | 49 | ||||
-rw-r--r-- | sys/dev/iwi/if_iwi_ioctl.h | 25 | ||||
-rw-r--r-- | sys/dev/iwi/if_iwireg.h | 63 | ||||
-rw-r--r-- | sys/dev/iwi/if_iwivar.h | 3 |
4 files changed, 138 insertions, 2 deletions
diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c index f013389..905e3b4 100644 --- a/sys/dev/iwi/if_iwi.c +++ b/sys/dev/iwi/if_iwi.c @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include <dev/iwi/if_iwireg.h> #include <dev/iwi/if_iwivar.h> +#include <dev/iwi/if_iwi_ioctl.h> #define IWI_DEBUG #ifdef IWI_DEBUG @@ -1373,6 +1374,33 @@ iwi_checkforqos(struct ieee80211vap *vap, #undef SUBTYPE } +static void +iwi_notif_link_quality(struct iwi_softc *sc, struct iwi_notif *notif) +{ + struct iwi_notif_link_quality *lq; + int len; + + len = le16toh(notif->len); + + DPRINTFN(5, ("Notification (%u) - len=%d, sizeof=%d\n", + notif->type, + len, + sizeof(struct iwi_notif_link_quality) + )); + + /* enforce length */ + if (len != sizeof(struct iwi_notif_link_quality)) { + DPRINTFN(5, ("Notification: (%u) too short (%d)\n", + notif->type, + len)); + return; + } + + lq = (struct iwi_notif_link_quality *)(notif + 1); + memcpy(&sc->sc_linkqual, lq, sizeof(sc->sc_linkqual)); + sc->sc_linkqual_valid = 1; +} + /* * Task queue callbacks for iwi_notification_intr used to avoid LOR's. */ @@ -1542,9 +1570,12 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) case IWI_NOTIF_TYPE_CALIBRATION: case IWI_NOTIF_TYPE_NOISE: - case IWI_NOTIF_TYPE_LINK_QUALITY: + /* XXX handle? */ DPRINTFN(5, ("Notification (%u)\n", notif->type)); break; + case IWI_NOTIF_TYPE_LINK_QUALITY: + iwi_notif_link_quality(sc, notif); + break; default: DPRINTF(("unknown notification type %u flags 0x%x len %u\n", @@ -2063,11 +2094,25 @@ iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGIFADDR: error = ether_ioctl(ifp, cmd, data); break; + case SIOCGIWISTATS: + IWI_LOCK(sc); + /* XXX validate permissions/memory/etc? */ + error = copyout(&sc->sc_linkqual, ifr->ifr_data, + sizeof(struct iwi_notif_link_quality)); + IWI_UNLOCK(sc); + break; + case SIOCZIWISTATS: + IWI_LOCK(sc); + memset(&sc->sc_linkqual, 0, + sizeof(struct iwi_notif_link_quality)); + IWI_UNLOCK(sc); + error = 0; + break; default: error = EINVAL; break; } - return error; + return error; } static void diff --git a/sys/dev/iwi/if_iwi_ioctl.h b/sys/dev/iwi/if_iwi_ioctl.h new file mode 100644 index 0000000..0f4f447 --- /dev/null +++ b/sys/dev/iwi/if_iwi_ioctl.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org> + * + * Permission to use, copy, modify, and 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. + * + * $FreeBSD$ + */ +#ifndef __IF_IWI_IOCTL_H__ +#define __IF_IWI_IOCTL_H__ + +/* XXX how should I pick appropriate ioctl numbers? */ +#define SIOCGIWISTATS _IOWR('i', 147, struct ifreq) +#define SIOCZIWISTATS _IOWR('i', 148, struct ifreq) + +#endif /* __IF_IWI_IOCTL_H__ */ diff --git a/sys/dev/iwi/if_iwireg.h b/sys/dev/iwi/if_iwireg.h index fb56fa5..bc05ad2 100644 --- a/sys/dev/iwi/if_iwireg.h +++ b/sys/dev/iwi/if_iwireg.h @@ -221,6 +221,7 @@ struct iwi_notif_association { /* structure for notification IWI_NOTIF_TYPE_SCAN_CHANNEL */ struct iwi_notif_scan_channel { uint8_t nchan; + /* XXX this is iwi_cmd_stats, and a u8 reserved field */ uint8_t reserved[47]; } __packed; @@ -239,6 +240,68 @@ struct iwi_notif_beacon_state { uint32_t number; } __packed; +/* structure(s) for notification IWI_NOTIF_TYPE_LINK_QUALITY */ + +#define RX_FREE_BUFFERS 32 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +// Used for passing to driver number of successes and failures per rate +struct iwi_rate_histogram { + union { + uint32_t a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + uint32_t b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + uint32_t g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + uint32_t a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + uint32_t b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + uint32_t g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __packed; + +/* statistics command response */ +struct iwi_cmd_stats { + uint8_t cmd_id; + uint8_t seq_num; + uint16_t good_sfd; + uint16_t bad_plcp; + uint16_t wrong_bssid; + uint16_t valid_mpdu; + uint16_t bad_mac_header; + uint16_t reserved_frame_types; + uint16_t rx_ina; + uint16_t bad_crc32; + uint16_t invalid_cts; + uint16_t invalid_acks; + uint16_t long_distance_ina_fina; + uint16_t dsp_silence_unreachable; + uint16_t accumulated_rssi; + uint16_t rx_ovfl_frame_tossed; + uint16_t rssi_silence_threshold; + uint16_t rx_ovfl_frame_supplied; + uint16_t last_rx_frame_signal; + uint16_t last_rx_frame_noise; + uint16_t rx_autodetec_no_ofdm; + uint16_t rx_autodetec_no_barker; + uint16_t reserved; +} __packed; + +#define SILENCE_OVER_THRESH (1) +#define SILENCE_UNDER_THRESH (2) + +struct iwi_notif_link_quality { + struct iwi_cmd_stats stats; + uint8_t rate; + uint8_t modulation; + struct iwi_rate_histogram histogram; + uint8_t silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */ + uint16_t silence_count; +} __packed; + /* received frame header */ struct iwi_frame { uint32_t reserved1[2]; diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h index 42ca92e..b38bbd9 100644 --- a/sys/dev/iwi/if_iwivar.h +++ b/sys/dev/iwi/if_iwivar.h @@ -215,6 +215,9 @@ struct iwi_softc { struct iwi_rx_radiotap_header sc_rxtap; struct iwi_tx_radiotap_header sc_txtap; + + struct iwi_notif_link_quality sc_linkqual; + int sc_linkqual_valid; }; #define IWI_STATE_BEGIN(_sc, _state) do { \ |