[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    ath(4): fix 11b/g ifmedia modes
From:       Stefan Sperling <stsp () stsp ! name>
Date:       2018-01-29 16:40:49
Message-ID: 20180129164049.GZ98299 () ted ! stsp ! name
[Download RAW message or body]

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,

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic