Hi, I reported this first in ath5k-devel, but now I'm convinced the problem lies in the cfg80211 regulatory framework. When there is more than one wireless card installed, sometimes the CRDA reply for first detected card's request gets into the kernel before next card is requested and everything is fine. But sometimes CRDA replies too late and kernel sends multiple request, one for each card. The behavior is completely random, different every boot. This is dmesg output from a system with three AR5414 PCI cards, all with regdomain 0x36 (Czech Republic) exhibiting this problem: ath5k 0000:02:01.0: PCI INT A -> GSI 22 (level, low) -> IRQ 22 ath5k 0000:02:01.0: registered as 'phy0' ath: EEPROM regdomain: 0x36 ath: EEPROM indicates we should expect a direct regpair map ath: Country alpha2 being used: CZ ath: Regpair used: 0x36 udev: renamed network interface eth0 to eth2 udev: renamed network interface eth1_rename to eth0 phy0: Selected rate control algorithm 'minstrel' ath5k phy0: Atheros AR5414 chip found (MAC: 0xa5, PHY: 0x61) ath5k 0000:02:02.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17 ath5k 0000:02:02.0: registered as 'phy1' ath: EEPROM regdomain: 0x36 ath: EEPROM indicates we should expect a direct regpair map ath: Country alpha2 being used: CZ ath: Regpair used: 0x36 cfg80211: Calling CRDA for country: CZ phy1: Selected rate control algorithm 'minstrel' ath5k phy1: Atheros AR5414 chip found (MAC: 0xa5, PHY: 0x61) ath5k 0000:02:03.0: PCI INT A -> GSI 19 (level, low) -> IRQ 19 ath5k 0000:02:03.0: registered as 'phy2' ath: EEPROM regdomain: 0x36 ath: EEPROM indicates we should expect a direct regpair map ath: Country alpha2 being used: CZ ath: Regpair used: 0x36 cfg80211: Calling CRDA for country: CZ udev: renamed network interface wlan1 to wlan3 phy2: Selected rate control algorithm 'minstrel' ath5k phy2: Atheros AR5414 chip found (MAC: 0xa5, PHY: 0x61) cfg80211: Calling CRDA for country: CZ udev: renamed network interface wlan1 to wlan2 cfg80211: Current regulatory domain intersected: (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp) (2402000 KHz - 2472000 KHz @ 40000 KHz), (N/A, 2000 mBm) (2457000 KHz - 2482000 KHz @ 20000 KHz), (N/A, 2000 mBm) (2474000 KHz - 2483500 KHz @ 9500 KHz), (N/A, 2000 mBm) (5170000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm) cfg80211: Current regulatory domain intersected: (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp) (2402000 KHz - 2472000 KHz @ 40000 KHz), (N/A, 2000 mBm) (2457000 KHz - 2482000 KHz @ 20000 KHz), (N/A, 2000 mBm) (2474000 KHz - 2483500 KHz @ 9500 KHz), (N/A, 2000 mBm) (5170000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm) cfg80211: Current regulatory domain intersected: (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp) (2402000 KHz - 2472000 KHz @ 40000 KHz), (N/A, 2000 mBm) (2457000 KHz - 2482000 KHz @ 20000 KHz), (N/A, 2000 mBm) (2474000 KHz - 2483500 KHz @ 9500 KHz), (N/A, 2000 mBm) (5170000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm) The result is that all but the last card stay in world regdomain with channels 100-140 unavailable. Only the last card has correct channels enabled. I had to disable some code at 4 places to get it working, so there might be mutiple bugs, or they all have some common cause, but I couldn't find any. The ugly patch I used is attached, hopefully it will provide some pointers to find out what's wrong. My guess is that the main problem is the use of the global variable last_request, which is incompatible with asynchronous replies from CRDA. Unfortunately it's quite hard for me to debug this problem because of the random behavior and especially because I don't understand the purpose of some parts of the regulatory code - for example why do you calculate the intersection at all, and don't just set on each card whatever regdomain is in its EEPROM? What should happen if all cards have different regdomains? Lukas Turek diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 422da20..52536ae 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1156,6 +1156,8 @@ static int freq_reg_info_regd(struct wiphy *wiphy, wiphy->regd) regd = wiphy->regd; + regd = cfg80211_regdomain; //HACK + if (!regd) return -EINVAL; @@ -1286,7 +1288,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, bw_flags = IEEE80211_CHAN_NO_HT40; if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && - request_wiphy && request_wiphy == wiphy && + request_wiphy && /* request_wiphy == wiphy && */ //HACK request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { /* * This gaurantees the driver's requested regulatory domain @@ -1327,6 +1329,8 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { + return false; //HACK + if (!last_request) return true; if (initiator == NL80211_REGDOM_SET_BY_CORE && @@ -2499,7 +2503,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { - intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + intersected_rd = regdom_intersect(rd, rd); //HACK if (!intersected_rd) return -EINVAL;
Attachment:
signature.asc
Description: This is a digitally signed message part.