Subject: ath stops when ifconfig changes some configuration values.
To: None <tech-net@netbsd.org>
From: Motoyuki OHMORI <ohmori@mobile-ip.org>
List: tech-net
Date: 09/09/2004 23:55:57
Hi,

I'm newbie and please let me know if it's wrong to ask this problem here.

I'm using an Atheros based wireless LAN card attached to cardbus.
Then, the card does not work after I change some value (e.g. nwid)
by ifconfig during ath is working.
dmesg shows:

	ath0: unable to reset hardware; hal status 3

I can get it worked again by 'ifconfig up'.
However, I think the cause is that ath_init() tries to set up the
card even after ath_stop() disables it.

I attached my patch against this problem and I hope it would be useful.

-- 
Motoyuki OHMORI <ohmori@mobile-ip.org>

Index: sys/dev/ic/ath.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/ath.c,v
retrieving revision 1.38
diff -c -r1.38 ath.c
*** dev/ic/ath.c	7 Sep 2004 01:15:59 -0000	1.38
--- dev/ic/ath.c	9 Sep 2004 14:20:21 -0000
***************
*** 130,136 ****
  #endif
  static int	ath_init1(struct ath_softc *);
  static int	ath_intr1(struct ath_softc *);
! static void	ath_stop(struct ifnet *);
  static void	ath_start(struct ifnet *);
  static void	ath_reset(struct ath_softc *);
  static int	ath_media_change(struct ifnet *);
--- 130,136 ----
  #endif
  static int	ath_init1(struct ath_softc *);
  static int	ath_intr1(struct ath_softc *);
! static void	ath_stop(struct ifnet *, int);
  static void	ath_start(struct ifnet *);
  static void	ath_reset(struct ath_softc *);
  static int	ath_media_change(struct ifnet *);
***************
*** 545,553 ****
  #ifdef __FreeBSD__
  	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  #else
! #if 0
! 	ifp->if_stop = ath_stop;		/* XXX */
! #endif
  	IFQ_SET_READY(&ifp->if_snd);
  #endif
  
--- 545,551 ----
  #ifdef __FreeBSD__
  	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  #else
! 	ifp->if_stop = ath_stop;
  	IFQ_SET_READY(&ifp->if_snd);
  #endif
  
***************
*** 643,649 ****
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
  	ath_softc_critsect_begin(sc, s);
! 	ath_stop(ifp);
  #if NBPFILTER > 0
  	bpfdetach(ifp);
  #endif
--- 641,647 ----
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
  	ath_softc_critsect_begin(sc, s);
! 	ath_stop(ifp, 0);
  #if NBPFILTER > 0
  	bpfdetach(ifp);
  #endif
***************
*** 672,677 ****
--- 670,676 ----
  ath_power(int why, void *arg)
  {
  	struct ath_softc *sc = arg;
+ 	struct ifnet *ifp = &sc->sc_ic.ic_if;
  	int s;
  
  	DPRINTF(ATH_DEBUG_ANY, ("ath_power(%d)\n", why));
***************
*** 680,689 ****
  	switch (why) {
  	case PWR_SUSPEND:
  	case PWR_STANDBY:
! 		ath_suspend(sc, why);
  		break;
  	case PWR_RESUME:
! 		ath_resume(sc, why);
  		break;
  	case PWR_SOFTSUSPEND:
  	case PWR_SOFTSTANDBY:
--- 679,689 ----
  	switch (why) {
  	case PWR_SUSPEND:
  	case PWR_STANDBY:
! 		ath_stop(ifp, 1);
  		break;
  	case PWR_RESUME:
! 		if (ifp->if_flags & IFF_UP)
! 			ath_init(ifp);
  		break;
  	case PWR_SOFTSUSPEND:
  	case PWR_SOFTSTANDBY:
***************
*** 701,707 ****
  
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
! 	ath_stop(ifp);
  	if (sc->sc_power != NULL)
  		(*sc->sc_power)(sc, why);
  }
--- 701,707 ----
  
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
! 	ath_stop(ifp, 0);
  	if (sc->sc_power != NULL)
  		(*sc->sc_power)(sc, why);
  }
***************
*** 731,737 ****
  {
  	struct ath_softc *sc = arg;
  
! 	ath_stop(&sc->sc_ic.ic_if);
  }
  #else
  void
--- 731,737 ----
  {
  	struct ath_softc *sc = arg;
  
! 	ath_stop(&sc->sc_ic.ic_if, 0);
  }
  #else
  void
***************
*** 744,750 ****
  
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
! 	ath_stop(ifp);
  #endif
  }
  #endif
--- 744,750 ----
  
  	DPRINTF(ATH_DEBUG_ANY, ("%s: if_flags %x\n", __func__, ifp->if_flags));
  
! 	ath_stop(ifp, 0);
  #endif
  }
  #endif
***************
*** 934,940 ****
  	 * Stop anything previously setup.  This is safe
  	 * whether this is the first time through or not.
  	 */
! 	ath_stop(ifp);
  
  	/*
  	 * The basic interface to setting the hardware in a good
--- 934,940 ----
  	 * Stop anything previously setup.  This is safe
  	 * whether this is the first time through or not.
  	 */
! 	ath_stop(ifp, 0);
  
  	/*
  	 * The basic interface to setting the hardware in a good
***************
*** 997,1003 ****
  }
  
  static void
! ath_stop(struct ifnet *ifp)
  {
  	struct ieee80211com *ic = (struct ieee80211com *) ifp;
  	struct ath_softc *sc = ifp->if_softc;
--- 997,1003 ----
  }
  
  static void
! ath_stop(struct ifnet *ifp, int disable)
  {
  	struct ieee80211com *ic = (struct ieee80211com *) ifp;
  	struct ath_softc *sc = ifp->if_softc;
***************
*** 1043,1049 ****
  			ath_hal_setpower(ah, HAL_PM_FULL_SLEEP, 0);
  		}
  #ifdef __NetBSD__
! 		ath_disable(sc);
  #endif
  	}
  	ath_softc_critsect_end(sc, s);
--- 1043,1050 ----
  			ath_hal_setpower(ah, HAL_PM_FULL_SLEEP, 0);
  		}
  #ifdef __NetBSD__
! 		if (disable)
! 			ath_disable(sc);
  #endif
  	}
  	ath_softc_critsect_end(sc, s);
***************
*** 1294,1300 ****
  					ath_init(ifp);	/* XXX lose error */
  			}
  		} else
! 			ath_stop(ifp);
  		break;
  	case SIOCADDMULTI:
  	case SIOCDELMULTI:
--- 1295,1301 ----
  					ath_init(ifp);	/* XXX lose error */
  			}
  		} else
! 			ath_stop(ifp, 1);
  		break;
  	case SIOCADDMULTI:
  	case SIOCDELMULTI: