mac80211: backport latest patches except for NVRAM support
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 313-brcmfmac-correct-interface-combination-info.patch
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
4
5 The interface combination provided by brcmfmac did not truly reflect
6 the combinations supported by driver and/or firmware.
7
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>
14 ---
15
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] =
19 }
20 };
21
22 +/**
23 + * brcmf_setup_ifmodes() - determine interface modes and combinations.
24 + *
25 + * @wiphy: wiphy object.
26 + * @ifp: interface object needed for feat module api.
27 + *
28 + * The interface modes and combinations are determined dynamically here
29 + * based on firmware functionality.
30 + *
31 + * no p2p and no mbss:
32 + *
33 + * #STA <= 1, #AP <= 1, channels = 1, 2 total
34 + *
35 + * no p2p and mbss:
36 + *
37 + * #STA <= 1, #AP <= 1, channels = 1, 2 total
38 + * #AP <= 4, matching BI, channels = 1, 4 total
39 + *
40 + * p2p, no mchan, and mbss:
41 + *
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
45 + *
46 + * p2p, mchan, and mbss:
47 + *
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
51 + */
52 static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
53 {
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;
60 + bool mbss, p2p;
61 + int i, c, n_combos;
62
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);
66 +
67 + n_combos = 1 + !!p2p + !!mbss;
68 + combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
69 if (!combo)
70 goto err;
71
72 - limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL);
73 - if (!limits)
74 + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
75 + if (!c0_limits)
76 goto err;
77
78 + if (p2p) {
79 + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
80 + if (!p2p_limits)
81 + goto err;
82 + }
83 +
84 + if (mbss) {
85 + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
86 + if (!mbss_limits)
87 + goto err;
88 + }
89 +
90 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
91 BIT(NL80211_IFTYPE_ADHOC) |
92 BIT(NL80211_IFTYPE_AP);
93
94 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
95 - combo->num_different_channels = 2;
96 - else
97 - combo->num_different_channels = 1;
98 -
99 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
100 - limits[i].max = 1;
101 - limits[i++].types = BIT(NL80211_IFTYPE_STATION);
102 - limits[i].max = 4;
103 - limits[i++].types = BIT(NL80211_IFTYPE_AP);
104 - max_iface_cnt = 5;
105 - } else {
106 - limits[i].max = 2;
107 - limits[i++].types = BIT(NL80211_IFTYPE_STATION) |
108 - BIT(NL80211_IFTYPE_AP);
109 - max_iface_cnt = 2;
110 - }
111 -
112 - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) {
113 + c = 0;
114 + i = 0;
115 + combo[c].num_different_channels = 1;
116 + c0_limits[i].max = 1;
117 + c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
118 + if (p2p) {
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);
124 - limits[i].max = 1;
125 - limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
126 - BIT(NL80211_IFTYPE_P2P_GO);
127 - limits[i].max = 1;
128 - limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
129 - max_iface_cnt += 2;
130 - }
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);
139 + } else {
140 + c0_limits[i].max = 1;
141 + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
142 + }
143 + combo[c].max_interfaces = i;
144 + combo[c].n_limits = i;
145 + combo[c].limits = c0_limits;
146 +
147 + if (p2p) {
148 + c++;
149 + i = 0;
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;
162 + }
163
164 + if (mbss) {
165 + c++;
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;
173 + }
174 + wiphy->n_iface_combinations = n_combos;
175 wiphy->iface_combinations = combo;
176 - wiphy->n_iface_combinations = 1;
177 return 0;
178
179 err:
180 - kfree(limits);
181 + kfree(c0_limits);
182 + kfree(p2p_limits);
183 + kfree(mbss_limits);
184 kfree(combo);
185 return -ENOMEM;
186 }
187 @@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier(
188
189 static void brcmf_free_wiphy(struct wiphy *wiphy)
190 {
191 + int i;
192 +
193 if (!wiphy)
194 return;
195
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);
201 + }
202 kfree(wiphy->iface_combinations);
203 if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
204 kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);