image.mk: fix emitting profiles for targets that have no subtargets
[openwrt/staging/yousong.git] / package / kernel / mac80211 / patches / 344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch
1 From: Franky Lin <frankyl@broadcom.com>
2 Date: Wed, 17 Feb 2016 11:26:55 +0100
3 Subject: [PATCH] brcmfmac: add neighbor discovery offload ip address table
4 configuration
5
6 Configure ipv6 address for neighbor discovery offload ip table in
7 firmware obtained through ipv6 address notification callback.
8
9 Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
10 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
11 Signed-off-by: Franky Lin <frankyl@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/broadcom/brcm80211/brcmfmac/cfg80211.c
17 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
18 @@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp,
19 }
20
21 static s32
22 -brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
23 +brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
24 {
25 s32 err;
26 u32 mode;
27 @@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf
28 enable, mode);
29 }
30
31 + err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
32 + if (err) {
33 + brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
34 + enable, err);
35 + err = 0;
36 + } else
37 + brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
38 + enable, mode);
39 +
40 return err;
41 }
42
43 @@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct
44 brcmf_report_wowl_wakeind(wiphy, ifp);
45 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
46 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
47 - brcmf_configure_arp_offload(ifp, true);
48 + brcmf_configure_arp_nd_offload(ifp, true);
49 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
50 cfg->wowl.pre_pmmode);
51 cfg->wowl.active = false;
52 @@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct
53
54 brcmf_dbg(TRACE, "Suspend, wowl config.\n");
55
56 - brcmf_configure_arp_offload(ifp, false);
57 + brcmf_configure_arp_nd_offload(ifp, false);
58 brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
59 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
60
61 @@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
62
63 if (!mbss) {
64 brcmf_set_mpc(ifp, 0);
65 - brcmf_configure_arp_offload(ifp, false);
66 + brcmf_configure_arp_nd_offload(ifp, false);
67 }
68
69 /* find the RSN_IE */
70 @@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
71 exit:
72 if ((err) && (!mbss)) {
73 brcmf_set_mpc(ifp, 1);
74 - brcmf_configure_arp_offload(ifp, true);
75 + brcmf_configure_arp_nd_offload(ifp, true);
76 }
77 return err;
78 }
79 @@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct
80 brcmf_err("bss_enable config failed %d\n", err);
81 }
82 brcmf_set_mpc(ifp, 1);
83 - brcmf_configure_arp_offload(ifp, true);
84 + brcmf_configure_arp_nd_offload(ifp, true);
85 clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
86 brcmf_net_setcarrier(ifp, false);
87
88 @@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct br
89 if (err)
90 goto default_conf_out;
91
92 - brcmf_configure_arp_offload(ifp, true);
93 + brcmf_configure_arp_nd_offload(ifp, true);
94
95 cfg->dongle_up = true;
96 default_conf_out:
97 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
98 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
99 @@ -20,6 +20,8 @@
100 #include <linux/inetdevice.h>
101 #include <net/cfg80211.h>
102 #include <net/rtnetlink.h>
103 +#include <net/addrconf.h>
104 +#include <net/ipv6.h>
105 #include <brcmu_utils.h>
106 #include <brcmu_wifi.h>
107
108 @@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struc
109 }
110 }
111
112 +#if IS_ENABLED(CONFIG_IPV6)
113 +static void _brcmf_update_ndtable(struct work_struct *work)
114 +{
115 + struct brcmf_if *ifp;
116 + int i, ret;
117 +
118 + ifp = container_of(work, struct brcmf_if, ndoffload_work);
119 +
120 + /* clear the table in firmware */
121 + ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
122 + if (ret) {
123 + brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
124 + return;
125 + }
126 +
127 + for (i = 0; i < ifp->ipv6addr_idx; i++) {
128 + ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
129 + &ifp->ipv6_addr_tbl[i],
130 + sizeof(struct in6_addr));
131 + if (ret)
132 + brcmf_err("add nd ip err %d\n", ret);
133 + }
134 +}
135 +#else
136 +static void _brcmf_update_ndtable(struct work_struct *work)
137 +{
138 +}
139 +#endif
140 +
141 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
142 {
143 struct brcmf_if *ifp = netdev_priv(ndev);
144 @@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *if
145
146 INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
147 INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
148 + INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
149
150 if (rtnl_locked)
151 err = register_netdevice(ndev);
152 @@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pu
153 if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
154 cancel_work_sync(&ifp->setmacaddr_work);
155 cancel_work_sync(&ifp->multicast_work);
156 + cancel_work_sync(&ifp->ndoffload_work);
157 }
158 brcmf_net_detach(ifp->ndev);
159 } else {
160 @@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct
161 }
162 #endif
163
164 +#if IS_ENABLED(CONFIG_IPV6)
165 +static int brcmf_inet6addr_changed(struct notifier_block *nb,
166 + unsigned long action, void *data)
167 +{
168 + struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
169 + inet6addr_notifier);
170 + struct inet6_ifaddr *ifa = data;
171 + struct brcmf_if *ifp;
172 + int i;
173 + struct in6_addr *table;
174 +
175 + /* Only handle primary interface */
176 + ifp = drvr->iflist[0];
177 + if (!ifp)
178 + return NOTIFY_DONE;
179 + if (ifp->ndev != ifa->idev->dev)
180 + return NOTIFY_DONE;
181 +
182 + table = ifp->ipv6_addr_tbl;
183 + for (i = 0; i < NDOL_MAX_ENTRIES; i++)
184 + if (ipv6_addr_equal(&ifa->addr, &table[i]))
185 + break;
186 +
187 + switch (action) {
188 + case NETDEV_UP:
189 + if (i == NDOL_MAX_ENTRIES) {
190 + if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
191 + table[ifp->ipv6addr_idx++] = ifa->addr;
192 + } else {
193 + for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
194 + table[i] = table[i + 1];
195 + table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
196 + }
197 + }
198 + break;
199 + case NETDEV_DOWN:
200 + if (i < NDOL_MAX_ENTRIES)
201 + for (; i < ifp->ipv6addr_idx; i++)
202 + table[i] = table[i + 1];
203 + break;
204 + default:
205 + break;
206 + }
207 +
208 + schedule_work(&ifp->ndoffload_work);
209 +
210 + return NOTIFY_OK;
211 +}
212 +#endif
213 +
214 int brcmf_attach(struct device *dev)
215 {
216 struct brcmf_pub *drvr = NULL;
217 @@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev)
218 #ifdef CONFIG_INET
219 drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
220 ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
221 + if (ret)
222 + goto fail;
223 +
224 +#if IS_ENABLED(CONFIG_IPV6)
225 + drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
226 + ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
227 + if (ret) {
228 + unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
229 + goto fail;
230 + }
231 #endif
232 +#endif /* CONFIG_INET */
233 +
234 + return 0;
235
236 fail:
237 - if (ret < 0) {
238 - brcmf_err("failed: %d\n", ret);
239 - if (drvr->config) {
240 - brcmf_cfg80211_detach(drvr->config);
241 - drvr->config = NULL;
242 - }
243 - if (drvr->fws) {
244 - brcmf_fws_del_interface(ifp);
245 - brcmf_fws_deinit(drvr);
246 - }
247 - if (ifp)
248 - brcmf_net_detach(ifp->ndev);
249 - if (p2p_ifp)
250 - brcmf_net_detach(p2p_ifp->ndev);
251 - drvr->iflist[0] = NULL;
252 - drvr->iflist[1] = NULL;
253 - if (brcmf_ignoring_probe_fail(drvr))
254 - ret = 0;
255 - return ret;
256 + brcmf_err("failed: %d\n", ret);
257 + if (drvr->config) {
258 + brcmf_cfg80211_detach(drvr->config);
259 + drvr->config = NULL;
260 + }
261 + if (drvr->fws) {
262 + brcmf_fws_del_interface(ifp);
263 + brcmf_fws_deinit(drvr);
264 }
265 - return 0;
266 + if (ifp)
267 + brcmf_net_detach(ifp->ndev);
268 + if (p2p_ifp)
269 + brcmf_net_detach(p2p_ifp->ndev);
270 + drvr->iflist[0] = NULL;
271 + drvr->iflist[1] = NULL;
272 + if (brcmf_ignoring_probe_fail(drvr))
273 + ret = 0;
274 +
275 + return ret;
276 }
277
278 void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
279 @@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev)
280 unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
281 #endif
282
283 +#if IS_ENABLED(CONFIG_IPV6)
284 + unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
285 +#endif
286 +
287 /* stop firmware event handling */
288 brcmf_fweh_detach(drvr);
289 if (drvr->config)
290 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
291 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
292 @@ -48,6 +48,8 @@
293 */
294 #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
295
296 +#define NDOL_MAX_ENTRIES 8
297 +
298 /**
299 * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
300 *
301 @@ -143,6 +145,7 @@ struct brcmf_pub {
302 #endif
303
304 struct notifier_block inetaddr_notifier;
305 + struct notifier_block inet6addr_notifier;
306 struct brcmf_mp_device *settings;
307 };
308
309 @@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason {
310 * @stats: interface specific network statistics.
311 * @setmacaddr_work: worker object for setting mac address.
312 * @multicast_work: worker object for multicast provisioning.
313 + * @ndoffload_work: worker object for neighbor discovery offload configuration.
314 * @fws_desc: interface specific firmware-signalling descriptor.
315 * @ifidx: interface index in device firmware.
316 * @bsscfgidx: index of bss associated with this interface.
317 @@ -191,6 +195,7 @@ struct brcmf_if {
318 struct net_device_stats stats;
319 struct work_struct setmacaddr_work;
320 struct work_struct multicast_work;
321 + struct work_struct ndoffload_work;
322 struct brcmf_fws_mac_descriptor *fws_desc;
323 int ifidx;
324 s32 bsscfgidx;
325 @@ -199,6 +204,8 @@ struct brcmf_if {
326 spinlock_t netif_stop_lock;
327 atomic_t pend_8021x_cnt;
328 wait_queue_head_t pend_8021x_wait;
329 + struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
330 + u8 ipv6addr_idx;
331 };
332
333 struct brcmf_skb_reorder_data {