mac80211: brcmfmac: fix support for BCM4366
mac80211: brcmfmac: fix support for BCM4366

1) Fix setting AP channel
2) Improve BSS management to avoid:
[ 3602.929199] brcmfmac: brcmf_ap_add_vif: timeout occurred

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@49383 3c298f89-4303-0410-b956-a3cf2f4a3e73

--- /dev/null
+++ b/package/kernel/mac80211/patches/351-0009-brcmfmac-print-errors-if-creating-interface-fails.patch
@@ -1,1 +1,60 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 27 May 2016 10:54:28 +0200
+Subject: [PATCH] brcmfmac: print errors if creating interface fails
 
+This is helpful for debugging. Without this all I was getting from "iw"
+command on failed creating of P2P interface was:
+> command failed: Too many open files in system (-23)
+
+Signed-off-by: Rafal Milecki <zajec5@gmail.com>
+[arend@broadcom.com: reduce error prints upon iface creation]
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -670,20 +670,24 @@ static struct wireless_dev *brcmf_cfg802
+ 		return ERR_PTR(-EOPNOTSUPP);
+ 	case NL80211_IFTYPE_AP:
+ 		wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
+-		if (!IS_ERR(wdev))
+-			brcmf_cfg80211_update_proto_addr_mode(wdev);
+-		return wdev;
++		break;
+ 	case NL80211_IFTYPE_P2P_CLIENT:
+ 	case NL80211_IFTYPE_P2P_GO:
+ 	case NL80211_IFTYPE_P2P_DEVICE:
+ 		wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
+-		if (!IS_ERR(wdev))
+-			brcmf_cfg80211_update_proto_addr_mode(wdev);
+-		return wdev;
++		break;
+ 	case NL80211_IFTYPE_UNSPECIFIED:
+ 	default:
+ 		return ERR_PTR(-EINVAL);
+ 	}
++
++	if (IS_ERR(wdev))
++		brcmf_err("add iface %s type %d failed: err=%d\n",
++			  name, type, (int)PTR_ERR(wdev));
++	else
++		brcmf_cfg80211_update_proto_addr_mode(wdev);
++
++	return wdev;
+ }
+ 
+ static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+@@ -2030,8 +2030,6 @@ static int brcmf_p2p_request_p2p_if(stru
+ 
+ 	err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
+ 				       sizeof(if_request));
+-	if (err)
+-		return err;
+ 
+ 	return err;
+ }
+

--- /dev/null
+++ b/package/kernel/mac80211/patches/351-0010-brcmfmac-fix-setting-AP-channel-with-new-firmwares.patch
@@ -1,1 +1,115 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 27 May 2016 21:07:19 +0200
+Subject: [PATCH] brcmfmac: fix setting AP channel with new firmwares
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Firmware for new chipsets is based on a new major version of code
+internally maintained at Broadcom. E.g. brcmfmac4366b-pcie.bin (used for
+BCM4366B1) is based on 10.10.69.3309 while brcmfmac43602-pcie.ap.bin was
+based on 7.35.177.56.
+
+Currently setting AP 5 GHz channel doesn't work reliably with BCM4366B1.
+When setting e.g. 36 control channel with VHT80 (center channel 42)
+firmware may randomly pick one of:
+1) 52 control channel with 58 as center one
+2) 100 control channel with 106 as center one
+3) 116 control channel with 122 as center one
+4) 149 control channel with 155 as center one
+
+It seems new firmwares require setting AP mode (BRCMF_C_SET_AP) before
+specifying a channel. Changing an order of firmware calls fixes the
+problem. This requirement resulted in two separated "chanspec" calls,
+one in AP code path and one in P2P path.
+
+This fix was verified with BCM4366B1 and tested for regressions on
+BCM43602.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -4398,7 +4398,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 	struct brcmf_join_params join_params;
+ 	enum nl80211_iftype dev_role;
+ 	struct brcmf_fil_bss_enable_le bss_enable;
+-	u16 chanspec;
++	u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
+ 	bool mbss;
+ 	int is_11d;
+ 
+@@ -4474,16 +4474,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 
+ 	brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
+ 
++	/* Parameters shared by all radio interfaces */
+ 	if (!mbss) {
+-		chanspec = chandef_to_chanspec(&cfg->d11inf,
+-					       &settings->chandef);
+-		err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
+-		if (err < 0) {
+-			brcmf_err("Set Channel failed: chspec=%d, %d\n",
+-				  chanspec, err);
+-			goto exit;
+-		}
+-
+ 		if (is_11d != ifp->vif->is_11d) {
+ 			err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
+ 						    is_11d);
+@@ -4531,6 +4523,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 		err = -EINVAL;
+ 		goto exit;
+ 	}
++
++	/* Interface specific setup */
+ 	if (dev_role == NL80211_IFTYPE_AP) {
+ 		if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
+ 			brcmf_fil_iovar_int_set(ifp, "mbss", 1);
+@@ -4540,6 +4534,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 			brcmf_err("setting AP mode failed %d\n", err);
+ 			goto exit;
+ 		}
++		if (!mbss) {
++			/* Firmware 10.x requires setting channel after enabling
++			 * AP and before bringing interface up.
++			 */
++			err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
++			if (err < 0) {
++				brcmf_err("Set Channel failed: chspec=%d, %d\n",
++					  chanspec, err);
++				goto exit;
++			}
++		}
+ 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+ 		if (err < 0) {
+ 			brcmf_err("BRCMF_C_UP error (%d)\n", err);
+@@ -4561,7 +4566,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 			goto exit;
+ 		}
+ 		brcmf_dbg(TRACE, "AP mode configuration complete\n");
+-	} else {
++	} else if (dev_role == NL80211_IFTYPE_P2P_GO) {
++		err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
++		if (err < 0) {
++			brcmf_err("Set Channel failed: chspec=%d, %d\n",
++				  chanspec, err);
++			goto exit;
++		}
+ 		err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
+ 						sizeof(ssid_le));
+ 		if (err < 0) {
+@@ -4578,7 +4589,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
+ 		}
+ 
+ 		brcmf_dbg(TRACE, "GO mode configuration complete\n");
++	} else {
++		WARN_ON(1);
+ 	}
++
+ 	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+ 	brcmf_net_setcarrier(ifp, true);
+ 
+

--- /dev/null
+++ b/package/kernel/mac80211/patches/351-0011-brcmfmac-don-t-remove-interface-on-link-down-firmwar.patch
@@ -1,1 +1,61 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 30 May 2016 06:40:54 +0200
+Subject: [PATCH] brcmfmac: don't remove interface on link down firmware event
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+There are two firmware events we handle similarly in brcmfmac:
+BRCMF_E_LINK and BRCMF_E_IF. The difference from firmware point of view
+is that the first one means BSS remains present in the firmware. Trying
+to (re)create it (e.g. when adding new virtual interface) will result in
+an error.
+
+Current code treats both events in a similar way. It removes Linux
+interface for each of them. It works OK with e.g. BCM43602. Its firmware
+generates both events for each interface. It means we get BRCMF_E_LINK
+and remove interface. That is soon followed by BRCMF_E_IF which means
+BSS was also removed in a firmware. The only downside of this is a
+harmless error like:
+[  208.643180] brcmfmac: brcmf_fweh_call_event_handler: no interface object
+
+Unfortunately BCM4366 firmware doesn't automatically remove BSS and so
+it doesn't generate BRCMF_E_IF. In such case we incorrectly remove Linux
+interface on BRCMF_E_LINK as BSS is still present in the firmware. It
+results in an error when trying to re-create virtual interface, e.g.:
+> iw phy phy1 interface add wlan1-1 type __ap
+[ 3602.929199] brcmfmac: brcmf_ap_add_vif: timeout occurred
+command failed: I/O error (-5)
+
+With this patch we don't remove Linux interface while firmware keeps
+BSS. Thanks to this we keep a consistent states of host driver and
+device firmware.
+
+Further improvement should be to mark BSS as disabled and remove
+interface on BRCMF_E_LINK. Then we should add support for reusing
+BSS-es.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -5388,7 +5388,6 @@ brcmf_notify_connect_status_ap(struct br
+ 			       struct net_device *ndev,
+ 			       const struct brcmf_event_msg *e, void *data)
+ {
+-	struct brcmf_if *ifp = netdev_priv(ndev);
+ 	static int generation;
+ 	u32 event = e->event_code;
+ 	u32 reason = e->reason;
+@@ -5399,8 +5398,6 @@ brcmf_notify_connect_status_ap(struct br
+ 	    ndev != cfg_to_ndev(cfg)) {
+ 		brcmf_dbg(CONN, "AP mode link down\n");
+ 		complete(&cfg->vif_disabled);
+-		if (ifp->vif->mbss)
+-			brcmf_remove_interface(ifp);
+ 		return 0;
+ 	}
+ 
+

--- a/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch
+++ b/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch
@@ -14,7 +14,7 @@
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2682,6 +2682,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2686,6 +2686,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
  	 * preference in cfg struct to apply this to
  	 * FW later while initializing the dongle
  	 */

comments