mac80211: backport latest patches except for NVRAM support
[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);