Our ath(4) driver has never supported 11g-mode-only devices, i.e. devices where ah_capabilities.cap_mode == MODE_11G. One such device is the AR5424: ath0 at pci6 dev 0 function 0 "Atheros AR5424" rev 0x01: apic 2 int 16 ath0: AR5424 14.2 phy 7.0 rf 10.2 eeprom 5.3 ...
It uses the same PHY as AR2425 devices, support for which was submitted recently here: https://marc.info/?l=openbsd-tech&m=151707056430848&w=2 I could make some progress with AR5424 in combination with that diff. It doesn't really work yet; it can associate, but Tx is very unreliable. There is one issue I'd like to fix in-tree already, which is that 11g mode doesn't show up in the list of supported media: $ ifconfig ath0 media ... supported media: media autoselect media autoselect mediaopt ibss media autoselect mediaopt hostap media autoselect mediaopt monitor This happens because the ath(4) driver doesn't set up 11g channel flags correctly. There is code which sets them up (ath_hal_init_channels) in a wrong way for 11g: It doesn't include 11b channels which are part of 11g. And later on there's a hack (ath_chan2flags) which effectively strips many important flag bits away and won't work for modes with overlapping channels, which is the case with 11b and 11g. As a result, some flags are missing from channels the driver reports to net80211, which then skips over those channels when building the media list. With the diff below and the AR2425 diff, the media list becomes: supported media: media autoselect media autoselect mediaopt ibss media autoselect mediaopt hostap media autoselect mediaopt monitor media autoselect mode 11b media autoselect mode 11b mediaopt ibss media autoselect mode 11b mediaopt hostap media autoselect mode 11b mediaopt monitor media autoselect mode 11g media autoselect mode 11g mediaopt ibss media autoselect mode 11g mediaopt hostap media autoselect mode 11g mediaopt monitor ok? Index: ar5211.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5211.c,v retrieving revision 1.49 diff -u -p -r1.49 ar5211.c --- ar5211.c 15 Oct 2017 13:06:12 -0000 1.49 +++ ar5211.c 29 Jan 2018 14:30:43 -0000 @@ -443,24 +443,25 @@ ar5k_ar5211_reset(struct ath_hal *hal, H */ hal->ah_op_mode = op_mode; - switch (channel->c_channel_flags & CHANNEL_MODES) { - case CHANNEL_A: + if ((channel->c_channel_flags & CHANNEL_A) == CHANNEL_A) { mode = AR5K_INI_VAL_11A; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - break; - case CHANNEL_B: - mode = AR5K_INI_VAL_11B; + } else if ((channel->c_channel_flags & CHANNEL_B) == CHANNEL_B) { + if (hal->ah_capabilities.cap_mode & HAL_MODE_11B) { + mode = AR5K_INI_VAL_11B; + ee_mode = AR5K_EEPROM_MODE_11B; + } else { + mode = AR5K_INI_VAL_11G; + ee_mode = AR5K_EEPROM_MODE_11G; + } freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11B; - break; - case CHANNEL_G: - case CHANNEL_PUREG: + } else if ((channel->c_channel_flags & (CHANNEL_G | CHANNEL_PUREG)) == + (CHANNEL_G | CHANNEL_PUREG)) { mode = AR5K_INI_VAL_11G; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11G; - break; - default: + } else { AR5K_PRINTF("invalid channel: %d\n", channel->c_channel); return (AH_FALSE); } Index: ar5212.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5212.c,v retrieving revision 1.57 diff -u -p -r1.57 ar5212.c --- ar5212.c 15 Oct 2017 13:06:12 -0000 1.57 +++ ar5212.c 29 Jan 2018 16:31:29 -0000 @@ -505,29 +505,30 @@ ar5k_ar5212_reset(struct ath_hal *hal, H */ hal->ah_op_mode = op_mode; - switch (channel->c_channel_flags & CHANNEL_MODES) { - case CHANNEL_A: + if ((channel->c_channel_flags & CHANNEL_A) == CHANNEL_A) { mode = AR5K_INI_VAL_11A; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - break; - case CHANNEL_B: - mode = AR5K_INI_VAL_11B; + } else if ((channel->c_channel_flags & CHANNEL_B) == CHANNEL_B) { + if (hal->ah_capabilities.cap_mode & HAL_MODE_11B) { + mode = AR5K_INI_VAL_11B; + ee_mode = AR5K_EEPROM_MODE_11B; + } else { + mode = AR5K_INI_VAL_11B; + mode = AR5K_INI_VAL_11G; + ee_mode = AR5K_EEPROM_MODE_11G; + } freq = AR5K_INI_RFGAIN_2GHZ; - ee_mode = AR5K_EEPROM_MODE_11B; - break; - case CHANNEL_G: - case CHANNEL_PUREG: + } else if ((channel->c_channel_flags & (CHANNEL_G | CHANNEL_PUREG)) == + (CHANNEL_G | CHANNEL_PUREG)) { mode = AR5K_INI_VAL_11G; freq = AR5K_INI_RFGAIN_2GHZ; ee_mode = AR5K_EEPROM_MODE_11G; - break; - case CHANNEL_XR: + } else if ((channel->c_channel_flags & CHANNEL_XR) == CHANNEL_XR) { mode = AR5K_INI_VAL_XR; freq = AR5K_INI_RFGAIN_5GHZ; ee_mode = AR5K_EEPROM_MODE_11A; - break; - default: + } else { AR5K_PRINTF("invalid channel: %d\n", channel->c_channel); return (AH_FALSE); } Index: ar5xxx.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5xxx.c,v retrieving revision 1.62 diff -u -p -r1.62 ar5xxx.c --- ar5xxx.c 25 Aug 2017 10:04:36 -0000 1.62 +++ ar5xxx.c 29 Jan 2018 16:31:29 -0000 @@ -472,11 +472,11 @@ ath_hal_init_channels(struct ath_hal *ha (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_CCK)) all_channels[c].c_channel_flags = CHANNEL_B; - if ((hal->ah_capabilities.cap_mode & HAL_MODE_11G) && - (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM)) { - all_channels[c].c_channel_flags |= - hal->ah_version == AR5K_AR5211 ? - CHANNEL_PUREG : CHANNEL_G; + if (hal->ah_capabilities.cap_mode & HAL_MODE_11G) { + if (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_CCK) + all_channels[c].c_channel_flags = CHANNEL_B; + if (ar5k_2ghz_channels[i].rc_mode & IEEE80211_CHAN_OFDM) + all_channels[c].c_channel_flags |= (CHANNEL_G | CHANNEL_PUREG); } /* Write channel and increment counter */ Index: ath.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ath.c,v retrieving revision 1.115 diff -u -p -r1.115 ath.c --- ath.c 31 May 2017 09:17:39 -0000 1.115 +++ ath.c 29 Jan 2018 15:02:21 -0000 @@ -88,7 +88,6 @@ int ath_ioctl(struct ifnet *, u_long, ca void ath_fatal_proc(void *, int); void ath_rxorn_proc(void *, int); void ath_bmiss_proc(void *, int); -u_int ath_chan2flags(struct ieee80211com *, struct ieee80211_channel *); int ath_initkeytable(struct ath_softc *); void ath_mcastfilter_accum(caddr_t, u_int32_t (*)[2]); void ath_mcastfilter_compute(struct ath_softc *, u_int32_t (*)[2]); @@ -601,26 +600,6 @@ ath_bmiss_proc(void *arg, int pending) } } -u_int -ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan) -{ - enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan); - - switch (mode) { - case IEEE80211_MODE_AUTO: - return 0; - case IEEE80211_MODE_11A: - return CHANNEL_A; - case IEEE80211_MODE_11B: - return CHANNEL_B; - case IEEE80211_MODE_11G: - return CHANNEL_G; - default: - panic("%s: unsupported mode %d", __func__, mode); - return 0; - } -} - int ath_init(struct ifnet *ifp) { @@ -666,7 +645,7 @@ ath_init1(struct ath_softc *sc) * and then setup of the interrupt mask. */ hchan.channel = ic->ic_ibss_chan->ic_freq; - hchan.channelFlags = ath_chan2flags(ic, ic->ic_ibss_chan); + hchan.channelFlags = ic->ic_ibss_chan->ic_flags; if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) { printf("%s: unable to reset hardware; hal status %u\n", ifp->if_xname, status); @@ -789,12 +768,11 @@ ath_reset(struct ath_softc *sc, int full HAL_CHANNEL hchan; /* - * Convert to a HAL channel description with the flags - * constrained to reflect the current operating mode. + * Convert to a HAL channel description. */ c = ic->ic_ibss_chan; hchan.channel = c->ic_freq; - hchan.channelFlags = ath_chan2flags(ic, c); + hchan.channelFlags = c->ic_flags; ath_hal_set_intr(ah, 0); /* disable interrupts */ ath_draintxq(sc); /* stop xmit side */ @@ -2658,12 +2636,10 @@ ath_chan_set(struct ath_softc *sc, struc ath_draintxq(sc); /* clear pending tx frames */ ath_stoprecv(sc); /* turn off frame recv */ /* - * Convert to a HAL channel description with - * the flags constrained to reflect the current - * operating mode. + * Convert to a HAL channel description. */ hchan.channel = chan->ic_freq; - hchan.channelFlags = ath_chan2flags(ic, chan); + hchan.channelFlags = chan->ic_flags; if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) { printf("%s: ath_chan_set: unable to reset " @@ -2753,12 +2729,11 @@ ath_calibrate(void *arg) sc->sc_stats.ast_per_cal++; /* - * Convert to a HAL channel description with the flags - * constrained to reflect the current operating mode. + * Convert to a HAL channel description. */ c = ic->ic_ibss_chan; hchan.channel = c->ic_freq; - hchan.channelFlags = ath_chan2flags(ic, c); + hchan.channelFlags = c->ic_flags; s = splnet(); DPRINTF(ATH_DEBUG_CALIBRATE,
