1 From: Arend van Spriel <arend@broadcom.com>
2 Date: Thu, 20 Aug 2015 22:06:03 +0200
3 Subject: [PATCH] brcmfmac: correct interface combination info
5 The interface combination provided by brcmfmac did not truly reflect
6 the combinations supported by driver and/or firmware.
8 Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
9 Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
10 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
11 Reviewed-by: Pontus Fuchs <pontusf@broadcom.com>
12 Signed-off-by: Arend van Spriel <arend@broadcom.com>
13 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
16 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
17 +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
18 @@ -5695,63 +5695,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
23 + * brcmf_setup_ifmodes() - determine interface modes and combinations.
25 + * @wiphy: wiphy object.
26 + * @ifp: interface object needed for feat module api.
28 + * The interface modes and combinations are determined dynamically here
29 + * based on firmware functionality.
31 + * no p2p and no mbss:
33 + * #STA <= 1, #AP <= 1, channels = 1, 2 total
37 + * #STA <= 1, #AP <= 1, channels = 1, 2 total
38 + * #AP <= 4, matching BI, channels = 1, 4 total
40 + * p2p, no mchan, and mbss:
42 + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
43 + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
44 + * #AP <= 4, matching BI, channels = 1, 4 total
46 + * p2p, mchan, and mbss:
48 + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
49 + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
50 + * #AP <= 4, matching BI, channels = 1, 4 total
52 static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
54 struct ieee80211_iface_combination *combo = NULL;
55 - struct ieee80211_iface_limit *limits = NULL;
56 - int i = 0, max_iface_cnt;
57 + struct ieee80211_iface_limit *c0_limits = NULL;
58 + struct ieee80211_iface_limit *p2p_limits = NULL;
59 + struct ieee80211_iface_limit *mbss_limits = NULL;
63 - combo = kzalloc(sizeof(*combo), GFP_KERNEL);
64 + mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
65 + p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
67 + n_combos = 1 + !!p2p + !!mbss;
68 + combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
72 - limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
74 + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
79 + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
85 + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
90 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
91 BIT(NL80211_IFTYPE_ADHOC) |
92 BIT(NL80211_IFTYPE_AP);
94 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
95 - combo->num_different_channels = 2;
97 - combo->num_different_channels = 1;
99 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
101 - limits[i++].types = BIT(NL80211_IFTYPE_STATION);
103 - limits[i++].types = BIT(NL80211_IFTYPE_AP);
107 - limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
108 - BIT(NL80211_IFTYPE_AP);
112 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
115 + combo[c].num_different_channels = 1;
116 + c0_limits[i].max = 1;
117 + c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
119 + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
120 + combo[c].num_different_channels = 2;
121 wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
122 BIT(NL80211_IFTYPE_P2P_GO) |
123 BIT(NL80211_IFTYPE_P2P_DEVICE);
125 - limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
126 - BIT(NL80211_IFTYPE_P2P_GO);
128 - limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
129 - max_iface_cnt += 2;
131 - combo->max_interfaces = max_iface_cnt;
132 - combo->limits = limits;
133 - combo->n_limits = i;
134 + c0_limits[i].max = 1;
135 + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
136 + c0_limits[i].max = 1;
137 + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
138 + BIT(NL80211_IFTYPE_P2P_GO);
140 + c0_limits[i].max = 1;
141 + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
143 + combo[c].max_interfaces = i;
144 + combo[c].n_limits = i;
145 + combo[c].limits = c0_limits;
150 + combo[c].num_different_channels = 1;
151 + p2p_limits[i].max = 1;
152 + p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
153 + p2p_limits[i].max = 1;
154 + p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP);
155 + p2p_limits[i].max = 1;
156 + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
157 + p2p_limits[i].max = 1;
158 + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
159 + combo[c].max_interfaces = i;
160 + combo[c].n_limits = i;
161 + combo[c].limits = p2p_limits;
166 + combo[c].beacon_int_infra_match = true;
167 + combo[c].num_different_channels = 1;
168 + mbss_limits[0].max = 4;
169 + mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
170 + combo[c].max_interfaces = 4;
171 + combo[c].n_limits = 1;
172 + combo[c].limits = mbss_limits;
174 + wiphy->n_iface_combinations = n_combos;
175 wiphy->iface_combinations = combo;
176 - wiphy->n_iface_combinations = 1;
183 + kfree(mbss_limits);
187 @@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier(
189 static void brcmf_free_wiphy(struct wiphy *wiphy)
196 - if (wiphy->iface_combinations)
197 - kfree(wiphy->iface_combinations->limits);
198 + if (wiphy->iface_combinations) {
199 + for (i = 0; i < wiphy->n_iface_combinations; i++)
200 + kfree(wiphy->iface_combinations[i].limits);
202 kfree(wiphy->iface_combinations);
203 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
204 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);