diff --git a/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch b/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch new file mode 100644 index 0000000000..97444b3c0d --- /dev/null +++ b/package/kernel/mac80211/patches/319-brcmfmac-consolidate-ifp-lookup-in-driver-core.patch @@ -0,0 +1,138 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:53 +0200 +Subject: [PATCH] brcmfmac: consolidate ifp lookup in driver core + +In rx path the firmware provide an interface index which is used to +map to a struct brcmf_if instance. However, this involves some trick +that is done in two places. This is changed by having driver core +providing brcmf_get_ifp() function. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -276,6 +276,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + struct sk_buff *pktbuf) + { + struct brcmf_proto_bcdc_header *h; ++ struct brcmf_if *ifp; + + brcmf_dbg(BCDC, "Enter\n"); + +@@ -289,30 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + trace_brcmf_bcdchdr(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +- *ifidx = BCDC_GET_IF_IDX(h); +- if (*ifidx >= BRCMF_MAX_IFS) { +- brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); ++ ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); ++ if (IS_ERR_OR_NULL(ifp)) { ++ brcmf_dbg(INFO, "no matching ifp found\n"); + return -EBADE; + } +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (*ifidx) +- (*ifidx)++; +- + if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != + BCDC_PROTO_VER) { + brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", +- brcmf_ifname(drvr, *ifidx), h->flags); ++ brcmf_ifname(drvr, ifp->ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BCDC_FLAG_SUM_GOOD) { + brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", +- brcmf_ifname(drvr, *ifidx), h->flags); ++ brcmf_ifname(drvr, ifp->ifidx), h->flags); + pktbuf->ip_summed = CHECKSUM_UNNECESSARY; + } + +@@ -320,12 +312,15 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); ++ brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2, ++ pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); + + if (pktbuf->len == 0) + return -ENODATA; ++ ++ *ifidx = ifp->ifidx; + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -83,6 +83,25 @@ char *brcmf_ifname(struct brcmf_pub *drv + return ""; + } + ++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx) ++{ ++ if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { ++ brcmf_err("ifidx %d out of range\n", ifidx); ++ return ERR_PTR(-ERANGE); ++ } ++ ++ /* The ifidx is the idx to map to matching netdev/ifp. When receiving ++ * events this is easy because it contains the bssidx which maps ++ * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. ++ * bssidx 1 is used for p2p0 and no data can be received or ++ * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 ++ */ ++ if (ifidx) ++ ifidx++; ++ ++ return drvr->iflist[ifidx]; ++} ++ + static void _brcmf_set_multicast_list(struct work_struct *work) + { + struct brcmf_if *ifp; +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -202,7 +202,7 @@ int brcmf_netdev_wait_pend8021x(struct b + + /* Return pointer to interface name */ + char *brcmf_ifname(struct brcmf_pub *drvr, int idx); +- ++struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, + char *name, u8 *mac_addr); +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -1081,16 +1081,8 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf + { + struct brcmf_if *ifp; + +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (ifidx) +- (ifidx)++; +- ifp = msgbuf->drvr->iflist[ifidx]; +- if (!ifp || !ifp->ndev) { ++ ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); ++ if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) { + brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); + brcmu_pkt_buf_free_skb(skb); + return; diff --git a/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch b/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch new file mode 100644 index 0000000000..632714ce24 --- /dev/null +++ b/package/kernel/mac80211/patches/320-brcmfmac-make-brcmf_proto_hdrpull-return-struct-brcm.patch @@ -0,0 +1,222 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:54 +0200 +Subject: [PATCH] brcmfmac: make brcmf_proto_hdrpull() return struct + brcmf_if instance + +Avoid spreading the ifidx in the driver, but have it return the +struct brcmf_if instance. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -272,11 +272,11 @@ brcmf_proto_bcdc_hdrpush(struct brcmf_pu + } + + static int +-brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +- struct sk_buff *pktbuf) ++brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, ++ struct sk_buff *pktbuf, struct brcmf_if **ifp) + { + struct brcmf_proto_bcdc_header *h; +- struct brcmf_if *ifp; ++ struct brcmf_if *tmp_if; + + brcmf_dbg(BCDC, "Enter\n"); + +@@ -290,21 +290,21 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + trace_brcmf_bcdchdr(pktbuf->data); + h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +- ifp = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); +- if (IS_ERR_OR_NULL(ifp)) { ++ tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); ++ if (!tmp_if) { + brcmf_dbg(INFO, "no matching ifp found\n"); + return -EBADE; + } + if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != + BCDC_PROTO_VER) { + brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", +- brcmf_ifname(drvr, ifp->ifidx), h->flags); ++ brcmf_ifname(drvr, tmp_if->ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BCDC_FLAG_SUM_GOOD) { + brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", +- brcmf_ifname(drvr, ifp->ifidx), h->flags); ++ brcmf_ifname(drvr, tmp_if->ifidx), h->flags); + pktbuf->ip_summed = CHECKSUM_UNNECESSARY; + } + +@@ -312,7 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, ifp->ifidx, h->data_offset << 2, ++ brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2, + pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); +@@ -320,7 +320,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + if (pktbuf->len == 0) + return -ENODATA; + +- *ifidx = ifp->ifidx; ++ *ifp = tmp_if; + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -87,7 +87,7 @@ struct brcmf_if *brcmf_get_ifp(struct br + { + if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { + brcmf_err("ifidx %d out of range\n", ifidx); +- return ERR_PTR(-ERANGE); ++ return NULL; + } + + /* The ifidx is the idx to map to matching netdev/ifp. When receiving +@@ -539,17 +539,15 @@ void brcmf_rx_frame(struct device *dev, + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_skb_reorder_data *rd; +- u8 ifidx; + int ret; + + brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); + + /* process and remove protocol-specific header */ +- ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); +- ifp = drvr->iflist[ifidx]; ++ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); + + if (ret || !ifp || !ifp->ndev) { +- if ((ret != -ENODATA) && ifp) ++ if (ret != -ENODATA && ifp) + ifp->stats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); + return; +@@ -592,17 +590,17 @@ void brcmf_txcomplete(struct device *dev + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +- u8 ifidx; ++ struct brcmf_if *ifp; + + /* await txstatus signal for firmware if active */ + if (brcmf_fws_fc_active(drvr->fws)) { + if (!success) + brcmf_fws_bustxfail(drvr->fws, txp); + } else { +- if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp)) ++ if (brcmf_proto_hdrpull(drvr, false, txp, &ifp)) + brcmu_pkt_buf_free_skb(txp); + else +- brcmf_txfinalize(drvr, txp, ifidx, success); ++ brcmf_txfinalize(drvr, txp, ifp->ifidx, success); + } + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1448,7 +1448,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + struct sk_buff *skb; + struct brcmf_skbuff_cb *skcb; + struct brcmf_fws_mac_descriptor *entry = NULL; +- u8 ifidx; ++ struct brcmf_if *ifp; + + brcmf_dbg(DATA, "flags %d\n", flags); + +@@ -1497,15 +1497,16 @@ brcmf_fws_txs_process(struct brcmf_fws_i + } + brcmf_fws_macdesc_return_req_credit(skb); + +- if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) { ++ ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp); ++ if (ret) { + brcmu_pkt_buf_free_skb(skb); + return -EINVAL; + } + if (!remove_from_hanger) +- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx, ++ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, + genbit, seq); + if (remove_from_hanger || ret) +- brcmf_txfinalize(fws->drvr, skb, ifidx, true); ++ brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true); + + return 0; + } +@@ -1848,7 +1849,7 @@ static int brcmf_fws_commit_skb(struct b + entry->transit_count--; + if (entry->suppressed) + entry->suppr_transit_count--; +- brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); ++ (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL); + goto rollback; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -522,7 +522,7 @@ static int brcmf_msgbuf_set_dcmd(struct + + + static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws, +- u8 *ifidx, struct sk_buff *skb) ++ struct sk_buff *skb, struct brcmf_if **ifp) + { + return -ENODEV; + } +@@ -1082,7 +1082,7 @@ brcmf_msgbuf_rx_skb(struct brcmf_msgbuf + struct brcmf_if *ifp; + + ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); +- if (IS_ERR_OR_NULL(ifp) || !ifp->ndev) { ++ if (!ifp || !ifp->ndev) { + brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); + brcmu_pkt_buf_free_skb(skb); + return; +--- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h +@@ -24,8 +24,8 @@ enum proto_addr_mode { + + + struct brcmf_proto { +- int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +- struct sk_buff *skb); ++ int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, ++ struct sk_buff *skb, struct brcmf_if **ifp); + int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len); + int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, +@@ -46,9 +46,19 @@ int brcmf_proto_attach(struct brcmf_pub + void brcmf_proto_detach(struct brcmf_pub *drvr); + + static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, +- u8 *ifidx, struct sk_buff *skb) ++ struct sk_buff *skb, ++ struct brcmf_if **ifp) + { +- return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb); ++ struct brcmf_if *tmp = NULL; ++ ++ /* assure protocol is always called with ++ * non-null initialized pointer. ++ */ ++ if (ifp) ++ *ifp = NULL; ++ else ++ ifp = &tmp; ++ return drvr->proto->hdrpull(drvr, do_fws, skb, ifp); + } + static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) diff --git a/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch b/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch new file mode 100644 index 0000000000..3360cbca82 --- /dev/null +++ b/package/kernel/mac80211/patches/321-brcmfmac-change-parameters-for-brcmf_remove_interfac.patch @@ -0,0 +1,87 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:55 +0200 +Subject: [PATCH] brcmfmac: change parameters for + brcmf_remove_interface() + +Just pass the interface to be removed, ie. the struct brcmf_if instance. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -4983,7 +4983,7 @@ brcmf_notify_connect_status_ap(struct br + brcmf_dbg(CONN, "AP mode link down\n"); + complete(&cfg->vif_disabled); + if (ifp->vif->mbss) +- brcmf_remove_interface(ifp->drvr, ifp->bssidx); ++ brcmf_remove_interface(ifp); + return 0; + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -887,12 +887,13 @@ static void brcmf_del_if(struct brcmf_pu + } + } + +-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx) ++void brcmf_remove_interface(struct brcmf_if *ifp) + { +- if (drvr->iflist[bssidx]) { +- brcmf_fws_del_interface(drvr->iflist[bssidx]); +- brcmf_del_if(drvr, bssidx); +- } ++ if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bssidx] != ifp)) ++ return; ++ ++ brcmf_fws_del_interface(ifp); ++ brcmf_del_if(ifp->drvr, ifp->bssidx); + } + + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) +@@ -1122,7 +1123,7 @@ void brcmf_detach(struct device *dev) + + /* make sure primary interface removed last */ + for (i = BRCMF_MAX_IFS-1; i > -1; i--) +- brcmf_remove_interface(drvr, i); ++ brcmf_remove_interface(drvr->iflist[i]); + + brcmf_cfg80211_detach(drvr->config); + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -206,7 +206,7 @@ struct brcmf_if *brcmf_get_ifp(struct br + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, + char *name, u8 *mac_addr); +-void brcmf_remove_interface(struct brcmf_pub *drvr, u32 bssidx); ++void brcmf_remove_interface(struct brcmf_if *ifp); + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -222,7 +222,7 @@ static void brcmf_fweh_handle_if_event(s + err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); + + if (ifp && ifevent->action == BRCMF_E_IF_DEL) +- brcmf_remove_interface(drvr, ifevent->bssidx); ++ brcmf_remove_interface(ifp); + } + + /** +--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +@@ -2140,7 +2140,7 @@ static void brcmf_p2p_delete_p2pdev(stru + { + cfg80211_unregister_wdev(&vif->wdev); + p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; +- brcmf_remove_interface(vif->ifp->drvr, vif->ifp->bssidx); ++ brcmf_remove_interface(vif->ifp); + brcmf_free_vif(vif); + } + diff --git a/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch b/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch new file mode 100644 index 0000000000..2b61f4eda5 --- /dev/null +++ b/package/kernel/mac80211/patches/322-brcmfmac-only-call-brcmf_cfg80211_detach-when-attach.patch @@ -0,0 +1,92 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:56 +0200 +Subject: [PATCH] brcmfmac: only call brcmf_cfg80211_detach() when attach + was successful + +In brcmf_bus_start() the function brcmf_cfg80211_attach() is called which +may fail. If this happens we should not call brcmf_cfg80211_detach() in +the failure path as it will result in NULL pointer dereference: + + brcmf_fweh_activate_events: Set event_msgs error (-5) + brcmf_bus_start: failed: -5 + brcmf_sdio_firmware_callback: dongle is not responding + BUG: unable to handle kernel NULL pointer dereference at 0000000000000068 + IP: [] kernfs_find_ns+0x18/0xd0 + PGD 0 + Oops: 0000 [#1] SMP + Modules linked in: brcmfmac(O) brcmutil(O) cfg80211 auth_rpcgss + CPU: 1 PID: 45 Comm: kworker/1:1 Tainted: G O + Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011 + Workqueue: events request_firmware_work_func + task: ffff880036c09ac0 ti: ffff880036dd4000 task.ti: ffff880036dd4000 + RIP: 0010:[] [] kernfs_find_ns+0x18/0xd0 + RSP: 0018:ffff880036dd7a28 EFLAGS: 00010246 + RAX: ffff880036c09ac0 RBX: 0000000000000000 RCX: 000000007fffffff + RDX: 0000000000000000 RSI: ffffffff816578b9 RDI: 0000000000000000 + RBP: ffff880036dd7a48 R08: 0000000000000000 R09: ffff880036c0b340 + R10: 00000000000002ec R11: ffff880036dd7b08 R12: ffffffff816578b9 + R13: 0000000000000000 R14: ffffffff816578b9 R15: ffff8800c6c87000 + FS: 0000000000000000(0000) GS:ffff88012bc40000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b + CR2: 0000000000000068 CR3: 0000000001a0b000 CR4: 00000000000006e0 + Stack: + 0000000000000000 ffffffff816578b9 0000000000000000 ffff8800c0d003c8 + ffff880036dd7a78 ffffffff811e8ff5 0000000ffffffff1 ffffffff81a9b060 + ffff8800c789f880 ffff8800c0d00000 ffff880036dd7a98 ffffffff811ebe0d + Call Trace: + [] kernfs_find_and_get_ns+0x35/0x60 + [] sysfs_unmerge_group+0x1d/0x60 + [] dpm_sysfs_remove+0x22/0x60 + [] device_del+0x49/0x240 + [] rfkill_unregister+0x58/0xc0 + [] wiphy_unregister+0xab/0x2f0 [cfg80211] + [] brcmf_cfg80211_detach+0x23/0x50 [brcmfmac] + [] brcmf_detach+0x86/0xe0 [brcmfmac] + [] brcmf_sdio_remove+0x48/0x120 [brcmfmac] + [] brcmf_sdiod_remove+0x29/0xd0 [brcmfmac] + [] brcmf_ops_sdio_remove+0xb1/0x110 [brcmfmac] + [] sdio_bus_remove+0x37/0x100 [mmc_core] + [] __device_release_driver+0x96/0x130 + [] device_release_driver+0x23/0x30 + [] brcmf_sdio_firmware_callback+0x2a8/0x5d0 [brcmfmac] + [] brcmf_fw_request_nvram_done+0x15f/0x5e0 [brcmfmac] + [] ? devres_add+0x3f/0x50 + [] ? usermodehelper_read_unlock+0x15/0x20 + [] ? platform_match+0x70/0xa0 + [] request_firmware_work_func+0x30/0x60 + [] process_one_work+0x14c/0x3d0 + [] worker_thread+0x11a/0x450 + [] ? process_one_work+0x3d0/0x3d0 + [] kthread+0xd2/0xf0 + [] ? kthread_create_on_node+0x180/0x180 + [] ret_from_fork+0x3f/0x70 + [] ? kthread_create_on_node+0x180/0x180 + Code: e9 40 fe ff ff 48 89 d8 eb 87 66 0f 1f 84 00 00 00 00 00 66 66 66 66 + 90 55 48 89 e5 41 56 49 89 f6 41 55 49 89 d5 31 d2 41 54 53 <0f> b7 + 47 68 48 8b 5f 48 66 c1 e8 05 83 e0 01 4d 85 ed 0f b6 c8 + RIP [] kernfs_find_ns+0x18/0xd0 + RSP + CR2: 0000000000000068 + ---[ end trace 87d6ec0d3fe46740 ]--- + +Reported-by: Daniel (Deognyoun) Kim +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -1049,7 +1049,10 @@ int brcmf_bus_start(struct device *dev) + fail: + if (ret < 0) { + brcmf_err("failed: %d\n", ret); +- brcmf_cfg80211_detach(drvr->config); ++ if (drvr->config) { ++ brcmf_cfg80211_detach(drvr->config); ++ drvr->config = NULL; ++ } + if (drvr->fws) { + brcmf_fws_del_interface(ifp); + brcmf_fws_deinit(drvr); diff --git a/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch b/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch new file mode 100644 index 0000000000..868b0a82e6 --- /dev/null +++ b/package/kernel/mac80211/patches/323-brcmfmac-correct-detection-of-p2pdev-interface-event.patch @@ -0,0 +1,105 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:57 +0200 +Subject: [PATCH] brcmfmac: correct detection of p2pdev interface event + +The p2pdev interface is setup in firmware resulting in a interface +event. This event has role and no-if flag. When role is p2p client +and no-if flag is set it indicates that this is the p2pdev interface. +This info is used in handling the event and adding interface in the +driver. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -795,7 +795,7 @@ fail: + } + + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, +- char *name, u8 *mac_addr) ++ bool is_p2pdev, char *name, u8 *mac_addr) + { + struct brcmf_if *ifp; + struct net_device *ndev; +@@ -821,7 +821,7 @@ struct brcmf_if *brcmf_add_if(struct brc + } + } + +- if (!brcmf_p2p_enable && bssidx == 1) { ++ if (!brcmf_p2p_enable && is_p2pdev) { + /* this is P2P_DEVICE interface */ + brcmf_dbg(INFO, "allocate non-netdev interface\n"); + ifp = kzalloc(sizeof(*ifp), GFP_KERNEL); +@@ -999,12 +999,12 @@ int brcmf_bus_start(struct device *dev) + brcmf_dbg(TRACE, "\n"); + + /* add primary networking interface */ +- ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL); ++ ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL); + if (IS_ERR(ifp)) + return PTR_ERR(ifp); + + if (brcmf_p2p_enable) +- p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); ++ p2p_ifp = brcmf_add_if(drvr, 1, 0, false, "p2p%d", NULL); + else + p2p_ifp = NULL; + if (IS_ERR(p2p_ifp)) +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -205,7 +205,7 @@ char *brcmf_ifname(struct brcmf_pub *drv + struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); + int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); + struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, +- char *name, u8 *mac_addr); ++ bool is_p2pdev, char *name, u8 *mac_addr); + void brcmf_remove_interface(struct brcmf_if *ifp); + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -179,6 +179,7 @@ static void brcmf_fweh_handle_if_event(s + { + struct brcmf_if_event *ifevent = data; + struct brcmf_if *ifp; ++ bool is_p2pdev; + int err = 0; + + brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n", +@@ -186,18 +187,16 @@ static void brcmf_fweh_handle_if_event(s + ifevent->flags, ifevent->role); + + /* The P2P Device interface event must not be ignored +- * contrary to what firmware tells us. The only way to +- * distinguish the P2P Device is by looking at the ifidx +- * and bssidx received. ++ * contrary to what firmware tells us. + */ +- if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) && +- (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { ++ is_p2pdev = (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && ++ ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT; ++ if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { + brcmf_dbg(EVENT, "event can be ignored\n"); + return; + } + if (ifevent->ifidx >= BRCMF_MAX_IFS) { +- brcmf_err("invalid interface index: %u\n", +- ifevent->ifidx); ++ brcmf_err("invalid interface index: %u\n", ifevent->ifidx); + return; + } + +@@ -207,7 +206,7 @@ static void brcmf_fweh_handle_if_event(s + brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, + emsg->addr); + ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, +- emsg->ifname, emsg->addr); ++ is_p2pdev, emsg->ifname, emsg->addr); + if (IS_ERR(ifp)) + return; + brcmf_fws_add_interface(ifp); diff --git a/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch b/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch new file mode 100644 index 0000000000..abd6681135 --- /dev/null +++ b/package/kernel/mac80211/patches/324-brcmfmac-use-brcmf_get_ifp-to-map-ifidx-to-struct-br.patch @@ -0,0 +1,126 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:58 +0200 +Subject: [PATCH] brcmfmac: use brcmf_get_ifp() to map ifidx to struct + brcmf_if instance + +The knowledge on how to map the interface index to a struct brcmf_if +instance is in brcmf_get_ifp() so use that function when only the +interface index is known instead of accessing brcmf_pub::iflist +directly. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c +@@ -149,7 +149,7 @@ static s32 brcmf_btcoex_params_read(stru + static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, + bool trump_sco) + { +- struct brcmf_if *ifp = btci->cfg->pub->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(btci->cfg->pub, 0); + + if (trump_sco && !btci->saved_regs_part2) { + /* this should reduce eSCO agressive +@@ -468,7 +468,7 @@ int brcmf_btcoex_set_mode(struct brcmf_c + { + struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy); + struct brcmf_btcoex_info *btci = cfg->btcoex; +- struct brcmf_if *ifp = cfg->pub->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + + switch (mode) { + case BRCMF_BTCOEX_DISABLED: +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -6213,7 +6213,7 @@ static void brcmf_free_wiphy(struct wiph + struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, + struct device *busdev) + { +- struct net_device *ndev = drvr->iflist[0]->ndev; ++ struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; + struct brcmf_cfg80211_info *cfg; + struct wiphy *wiphy; + struct brcmf_cfg80211_vif *vif; +--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c +@@ -121,7 +121,7 @@ static void brcmf_feat_iovar_int_set(str + + void brcmf_feat_attach(struct brcmf_pub *drvr) + { +- struct brcmf_if *ifp = drvr->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); +--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +@@ -221,7 +221,7 @@ static void brcmf_flowring_block(struct + + bus_if = dev_get_drvdata(flow->dev); + drvr = bus_if->drvr; +- ifp = drvr->iflist[ifidx]; ++ ifp = brcmf_get_ifp(drvr, ifidx); + brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked); + + spin_unlock_irqrestore(&flow->block_lock, flags); +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -334,7 +334,7 @@ void brcmf_fweh_attach(struct brcmf_pub + void brcmf_fweh_detach(struct brcmf_pub *drvr) + { + struct brcmf_fweh_info *fweh = &drvr->fweh; +- struct brcmf_if *ifp = drvr->iflist[0]; ++ struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + + if (ifp) { +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -972,7 +972,7 @@ static void + brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq, + u8 if_id) + { +- struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1]; ++ struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id); + + if (WARN_ON(!ifp)) + return; +@@ -2118,6 +2118,7 @@ static int brcmf_debugfs_fws_stats_read( + int brcmf_fws_init(struct brcmf_pub *drvr) + { + struct brcmf_fws_info *fws; ++ struct brcmf_if *ifp; + u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; + int rc; + u32 mode; +@@ -2177,21 +2178,22 @@ int brcmf_fws_init(struct brcmf_pub *drv + * continue. Set mode back to none indicating not enabled. + */ + fws->fw_signals = true; +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) { ++ ifp = brcmf_get_ifp(drvr, 0); ++ if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) { + brcmf_err("failed to set bdcv2 tlv signaling\n"); + fws->fcmode = BRCMF_FWS_FCMODE_NONE; + fws->fw_signals = false; + } + +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) ++ if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1)) + brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); + + /* Enable seq number reuse, if supported */ +- if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) { ++ if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) { + if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) { + mode = 0; + BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1); +- if (brcmf_fil_iovar_int_set(drvr->iflist[0], ++ if (brcmf_fil_iovar_int_set(ifp, + "wlfc_mode", mode) == 0) { + BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1); + } diff --git a/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch b/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch new file mode 100644 index 0000000000..23a7b6f1c8 --- /dev/null +++ b/package/kernel/mac80211/patches/325-brcmfmac-pass-struct-brcmf_if-instance-in-brcmf_txfi.patch @@ -0,0 +1,122 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:14:59 +0200 +Subject: [PATCH] brcmfmac: pass struct brcmf_if instance in + brcmf_txfinalize() + +Most call sites of brcmf_txfinalize already have struct brcmf_if +instance so pass that to brcmf_txfinalize() as the function +needs it anyway. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -560,17 +560,11 @@ void brcmf_rx_frame(struct device *dev, + brcmf_netif_rx(ifp, skb); + } + +-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, +- bool success) ++void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) + { +- struct brcmf_if *ifp; + struct ethhdr *eh; + u16 type; + +- ifp = drvr->iflist[ifidx]; +- if (!ifp) +- goto done; +- + eh = (struct ethhdr *)(txp->data); + type = ntohs(eh->h_proto); + +@@ -582,7 +576,7 @@ void brcmf_txfinalize(struct brcmf_pub * + + if (!success) + ifp->stats.tx_errors++; +-done: ++ + brcmu_pkt_buf_free_skb(txp); + } + +@@ -600,7 +594,7 @@ void brcmf_txcomplete(struct device *dev + if (brcmf_proto_hdrpull(drvr, false, txp, &ifp)) + brcmu_pkt_buf_free_skb(txp); + else +- brcmf_txfinalize(drvr, txp, ifp->ifidx, success); ++ brcmf_txfinalize(ifp, txp, success); + } + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -210,8 +210,7 @@ void brcmf_remove_interface(struct brcmf + int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + void brcmf_txflowblock_if(struct brcmf_if *ifp, + enum brcmf_netif_stop_reason reason, bool state); +-void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, +- bool success); ++void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); + void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); + + /* Sets dongle media info (drv_version, mac address). */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1506,7 +1506,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, + genbit, seq); + if (remove_from_hanger || ret) +- brcmf_txfinalize(fws->drvr, skb, ifp->ifidx, true); ++ brcmf_txfinalize(ifp, skb, true); + + return 0; + } +@@ -1905,7 +1905,7 @@ int brcmf_fws_process_skb(struct brcmf_i + if (fws->avoid_queueing) { + rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb); + if (rc < 0) +- brcmf_txfinalize(drvr, skb, ifp->ifidx, false); ++ brcmf_txfinalize(ifp, skb, false); + return rc; + } + +@@ -1929,7 +1929,7 @@ int brcmf_fws_process_skb(struct brcmf_i + brcmf_fws_schedule_deq(fws); + } else { + brcmf_err("drop skb: no hanger slot\n"); +- brcmf_txfinalize(drvr, skb, ifp->ifidx, false); ++ brcmf_txfinalize(ifp, skb, false); + rc = -ENOMEM; + } + brcmf_fws_unlock(fws); +@@ -2009,8 +2009,9 @@ static void brcmf_fws_dequeue_worker(str + ret = brcmf_proto_txdata(drvr, ifidx, 0, skb); + brcmf_fws_lock(fws); + if (ret < 0) +- brcmf_txfinalize(drvr, skb, ifidx, +- false); ++ brcmf_txfinalize(brcmf_get_ifp(drvr, ++ ifidx), ++ skb, false); + if (fws->bus_flow_blocked) + break; + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -873,7 +873,11 @@ brcmf_msgbuf_process_txstatus(struct brc + commonring = msgbuf->flowrings[flowid]; + atomic_dec(&commonring->outstanding_tx); + +- brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true); ++ /* Hante: i believe this was a bug as tx_status->msg.ifidx was used ++ * in brcmf_txfinalize as index in drvr->iflist. Can you confirm/deny? ++ */ ++ brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx), ++ skb, true); + } + + diff --git a/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch b/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch new file mode 100644 index 0000000000..8ddc0a6eef --- /dev/null +++ b/package/kernel/mac80211/patches/326-brcmfmac-add-mapping-for-interface-index-to-bsscfg-i.patch @@ -0,0 +1,92 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:15:00 +0200 +Subject: [PATCH] brcmfmac: add mapping for interface index to bsscfg + index + +Because the P2P Device interface in firmware uses the same interface +index as the primary interface we use the bsscfg index as index in the +struct brcmf_pub::iflist. However, in the data path we get the interface +index and not the bsscfg index. So we need a mapping of interface index +to bsscfg index, which can be determined upon handle adding the interface. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -85,21 +85,20 @@ char *brcmf_ifname(struct brcmf_pub *drv + + struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx) + { ++ struct brcmf_if *ifp; ++ s32 bssidx; ++ + if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { + brcmf_err("ifidx %d out of range\n", ifidx); + return NULL; + } + +- /* The ifidx is the idx to map to matching netdev/ifp. When receiving +- * events this is easy because it contains the bssidx which maps +- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +- * bssidx 1 is used for p2p0 and no data can be received or +- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +- */ +- if (ifidx) +- ifidx++; ++ ifp = NULL; ++ bssidx = drvr->if2bss[ifidx]; ++ if (bssidx >= 0) ++ ifp = drvr->iflist[bssidx]; + +- return drvr->iflist[ifidx]; ++ return ifp; + } + + static void _brcmf_set_multicast_list(struct work_struct *work) +@@ -831,6 +830,8 @@ struct brcmf_if *brcmf_add_if(struct brc + + ifp = netdev_priv(ndev); + ifp->ndev = ndev; ++ /* store mapping ifidx to bssidx */ ++ drvr->if2bss[ifidx] = bssidx; + } + + ifp->drvr = drvr; +@@ -855,6 +856,7 @@ static void brcmf_del_if(struct brcmf_pu + struct brcmf_if *ifp; + + ifp = drvr->iflist[bssidx]; ++ drvr->if2bss[ifp->ifidx] = -1; + drvr->iflist[bssidx] = NULL; + if (!ifp) { + brcmf_err("Null interface, idx=%d\n", bssidx); +@@ -862,6 +864,7 @@ static void brcmf_del_if(struct brcmf_pu + } + brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); + if (ifp->ndev) { ++ drvr->if2bss[ifp->ifidx] = -1; + if (bssidx == 0) { + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + rtnl_lock(); +@@ -926,6 +929,7 @@ int brcmf_attach(struct device *dev) + if (!drvr) + return -ENOMEM; + ++ memset(drvr->if2bss, 0xFF, sizeof(drvr->if2bss)); + mutex_init(&drvr->proto_block); + + /* Link to bus module */ +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h +@@ -122,6 +122,7 @@ struct brcmf_pub { + struct mac_address addresses[BRCMF_MAX_IFS]; + + struct brcmf_if *iflist[BRCMF_MAX_IFS]; ++ s32 if2bss[BRCMF_MAX_IFS]; + + struct mutex proto_block; + unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; diff --git a/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch b/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch new file mode 100644 index 0000000000..a0a798be93 --- /dev/null +++ b/package/kernel/mac80211/patches/327-brcmfmac-add-dedicated-debug-level-for-firmware-cons.patch @@ -0,0 +1,103 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:15:01 +0200 +Subject: [PATCH] brcmfmac: add dedicated debug level for firmware + console logging + +Both PCIe and SDIO devices have the possibility to log the firmware +console output in kernel log. For PCIe it is logged when PCIE debug +level is enabled. For SDIO it is logged when user specifies a non-zero +console interval through debugfs. This patch tries to make it a +bit more consistent. The firmware console output is only logged when +FWCON debug level is enabled. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Pontus Fuchs +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h +@@ -37,6 +37,7 @@ + #define BRCMF_SDIO_VAL 0x00020000 + #define BRCMF_MSGBUF_VAL 0x00040000 + #define BRCMF_PCIE_VAL 0x00080000 ++#define BRCMF_FWCON_VAL 0x00100000 + + /* set default print format */ + #undef pr_fmt +@@ -78,6 +79,7 @@ do { \ + #define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) + #define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) + #define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL) ++#define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL) + + #else /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */ + +@@ -90,6 +92,7 @@ do { \ + #define BRCMF_GLOM_ON() 0 + #define BRCMF_EVENT_ON() 0 + #define BRCMF_FIL_ON() 0 ++#define BRCMF_FWCON_ON() 0 + + #endif /* defined(DEBUG) || defined(CPTCFG_BRCM_TRACING) */ + +--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +@@ -644,7 +644,7 @@ static void brcmf_pcie_bus_console_init( + addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET; + console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr); + +- brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n", ++ brcmf_dbg(FWCON, "Console: base %x, buf %x, size %d\n", + console->base_addr, console->buf_addr, console->bufsize); + } + +@@ -656,6 +656,9 @@ static void brcmf_pcie_bus_console_read( + u8 ch; + u32 newidx; + ++ if (!BRCMF_FWCON_ON()) ++ return; ++ + console = &devinfo->shared.console; + addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET; + newidx = brcmf_pcie_read_tcm32(devinfo, addr); +@@ -677,7 +680,7 @@ static void brcmf_pcie_bus_console_read( + } + if (ch == '\n') { + console->log_str[console->log_idx] = 0; +- brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str); ++ pr_debug("CONSOLE: %s", console->log_str); + console->log_idx = 0; + } + } +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -123,6 +123,7 @@ struct rte_console { + + #define BRCMF_FIRSTREAD (1 << 6) + ++#define BRCMF_CONSOLE 10 /* watchdog interval to poll console */ + + /* SBSDIO_DEVICE_CTL */ + +@@ -3204,6 +3205,8 @@ static void brcmf_sdio_debugfs_create(st + if (IS_ERR_OR_NULL(dentry)) + return; + ++ bus->console_interval = BRCMF_CONSOLE; ++ + brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read); + brcmf_debugfs_add_entry(drvr, "counters", + brcmf_debugfs_sdio_count_read); +@@ -3613,7 +3616,7 @@ static void brcmf_sdio_bus_watchdog(stru + } + #ifdef DEBUG + /* Poll for console output periodically */ +- if (bus->sdiodev->state == BRCMF_SDIOD_DATA && ++ if (bus->sdiodev->state == BRCMF_SDIOD_DATA && BRCMF_FWCON_ON() && + bus->console_interval != 0) { + bus->console.count += BRCMF_WD_POLL_MS; + if (bus->console.count >= bus->console_interval) { diff --git a/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch b/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch new file mode 100644 index 0000000000..53e7edeee7 --- /dev/null +++ b/package/kernel/mac80211/patches/328-brcmfmac-remove-ifidx-parameter-from-brcmf_fws_txsta.patch @@ -0,0 +1,34 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:15:02 +0200 +Subject: [PATCH] brcmfmac: remove ifidx parameter from + brcmf_fws_txstatus_suppressed() + +The brcmf_fws_txstatus_suppressed() function prototype specifies an +ifidx parameter which is not used within the function implementation. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1398,7 +1398,7 @@ done: + } + + static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, +- struct sk_buff *skb, u8 ifidx, ++ struct sk_buff *skb, + u32 genbit, u16 seq) + { + struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; +@@ -1503,7 +1503,7 @@ brcmf_fws_txs_process(struct brcmf_fws_i + return -EINVAL; + } + if (!remove_from_hanger) +- ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifp->ifidx, ++ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, + genbit, seq); + if (remove_from_hanger || ret) + brcmf_txfinalize(ifp, skb, true); diff --git a/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch b/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch new file mode 100644 index 0000000000..bb05235cf4 --- /dev/null +++ b/package/kernel/mac80211/patches/329-brcmfmac-change-prototype-for-brcmf_fws_hdrpull.patch @@ -0,0 +1,97 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:15:03 +0200 +Subject: [PATCH] brcmfmac: change prototype for brcmf_fws_hdrpull() + +Instead of passing ifidx and drvr just pass struct brcmf_if pointer +which holds both parameters. + +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +@@ -312,8 +312,7 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pu + + skb_pull(pktbuf, BCDC_HEADER_LEN); + if (do_fws) +- brcmf_fws_hdrpull(drvr, tmp_if->ifidx, h->data_offset << 2, +- pktbuf); ++ brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf); + else + skb_pull(pktbuf, h->data_offset << 2); + +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +@@ -1616,11 +1616,10 @@ static int brcmf_fws_notify_bcmc_credit_ + return 0; + } + +-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, +- struct sk_buff *skb) ++void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) + { + struct brcmf_skb_reorder_data *rd; +- struct brcmf_fws_info *fws = drvr->fws; ++ struct brcmf_fws_info *fws = ifp->drvr->fws; + u8 *signal_data; + s16 data_len; + u8 type; +@@ -1630,20 +1629,20 @@ int brcmf_fws_hdrpull(struct brcmf_pub * + s32 err; + + brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n", +- ifidx, skb->len, signal_len); ++ ifp->ifidx, skb->len, siglen); + +- WARN_ON(signal_len > skb->len); ++ WARN_ON(siglen > skb->len); + +- if (!signal_len) +- return 0; ++ if (!siglen) ++ return; + /* if flow control disabled, skip to packet data and leave */ + if ((!fws) || (!fws->fw_signals)) { +- skb_pull(skb, signal_len); +- return 0; ++ skb_pull(skb, siglen); ++ return; + } + + fws->stats.header_pulls++; +- data_len = signal_len; ++ data_len = siglen; + signal_data = skb->data; + + status = BRCMF_FWS_RET_OK_NOSCHEDULE; +@@ -1731,14 +1730,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub * + /* signalling processing result does + * not affect the actual ethernet packet. + */ +- skb_pull(skb, signal_len); ++ skb_pull(skb, siglen); + + /* this may be a signal-only packet + */ + if (skb->len == 0) + fws->stats.header_only_pkt++; +- +- return 0; + } + + static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h +@@ -21,8 +21,7 @@ + int brcmf_fws_init(struct brcmf_pub *drvr); + void brcmf_fws_deinit(struct brcmf_pub *drvr); + bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); +-int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, +- struct sk_buff *skb); ++void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); + int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb); + + void brcmf_fws_reset_interface(struct brcmf_if *ifp); diff --git a/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch b/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch new file mode 100644 index 0000000000..0651a2f027 --- /dev/null +++ b/package/kernel/mac80211/patches/330-brcmfmac-introduce-brcmf_net_detach-function.patch @@ -0,0 +1,99 @@ +From: Arend van Spriel +Date: Wed, 26 Aug 2015 22:15:04 +0200 +Subject: [PATCH] brcmfmac: introduce brcmf_net_detach() function + +In case of error during brcmf_bus_start() the network interfaces were +freed using free_netdev(). However, the interfaces may have additional +memory allocated which is not freed. The netdev has destructor set to +brcmf_cfg80211_free_netdev() which frees the additional memory if +allocated and call free_netdev(). The brcmf_net_detach() either calls +brcmf_cfg80211_free_netdev() directly or uses unregister_netdev() when +struct net_device::reg_state indicates the netdev was registered. + +Reported-by: Daniel (Deognyoun) Kim +Reviewed-by: Hante Meuleman +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +--- + +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -4747,7 +4747,8 @@ void brcmf_cfg80211_free_netdev(struct n + ifp = netdev_priv(ndev); + vif = ifp->vif; + +- brcmf_free_vif(vif); ++ if (vif) ++ brcmf_free_vif(vif); + free_netdev(ndev); + } + +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *if + } + + brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); +- +- ndev->destructor = brcmf_cfg80211_free_netdev; + return 0; + + fail: +@@ -729,6 +727,14 @@ fail: + return -EBADE; + } + ++static void brcmf_net_detach(struct net_device *ndev) ++{ ++ if (ndev->reg_state == NETREG_REGISTERED) ++ unregister_netdev(ndev); ++ else ++ brcmf_cfg80211_free_netdev(ndev); ++} ++ + static int brcmf_net_p2p_open(struct net_device *ndev) + { + brcmf_dbg(TRACE, "Enter\n"); +@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brc + ifp->ndev->name); + if (ifidx) { + netif_stop_queue(ifp->ndev); +- unregister_netdev(ifp->ndev); +- free_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + drvr->iflist[bssidx] = NULL; + } else { + brcmf_err("ignore IF event\n"); +@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brc + if (!ndev) + return ERR_PTR(-ENOMEM); + ++ ndev->destructor = brcmf_cfg80211_free_netdev; + ifp = netdev_priv(ndev); + ifp->ndev = ndev; + /* store mapping ifidx to bssidx */ +@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pu + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); + } +- /* unregister will take care of freeing it */ +- unregister_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + } + } + +@@ -1056,11 +1061,11 @@ fail: + brcmf_fws_deinit(drvr); + } + if (drvr->iflist[0]) { +- free_netdev(ifp->ndev); ++ brcmf_net_detach(ifp->ndev); + drvr->iflist[0] = NULL; + } + if (p2p_ifp) { +- free_netdev(p2p_ifp->ndev); ++ brcmf_net_detach(p2p_ifp->ndev); + drvr->iflist[1] = NULL; + } + return ret;