}
u32 brcmf_sdiod_readl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
-@@ -272,11 +256,16 @@ u32 brcmf_sdiod_readl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
+@@ -272,11 +256,16 @@ u32 brcmf_sdiod_readl(struct brcmf_sdio_
u32 data = 0;
int retval;
if (ret)
*ret = retval;
}
-@@ -540,10 +534,13 @@ int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)
+@@ -540,10 +534,13 @@ int brcmf_sdiod_recv_pkt(struct brcmf_sd
brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len);
--- /dev/null
+From 5242a5444e0b6464d7455beb55d936dd192b5e9d Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Mon, 22 Jan 2018 21:46:39 +0100
+Subject: [PATCH] brcmfmac: assure bcdc dcmd api does not return value > 0
+
+The protocol layer api defines callbacks for dongle commands.
+Although not really well documented these should only return an
+error code in case of an error, or 0 upon success. In the bcdc
+protocol it can return value above 0 and we carry a fix in the
+caller of the protocol layer api. This patch makes it adhere to
+the intent of the api as described above.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 6 +++++-
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 8 +++-----
+ 2 files changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+@@ -211,6 +211,8 @@ retry:
+ memcpy(buf, info, len);
+ }
+
++ ret = 0;
++
+ /* Check the ERROR flag */
+ if (flags & BCDC_DCMD_ERROR)
+ ret = le32_to_cpu(msg->status);
+@@ -225,7 +227,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
+ {
+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+ struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+- int ret = 0;
++ int ret;
+ u32 flags, id;
+
+ brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
+@@ -249,6 +251,8 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
+ goto done;
+ }
+
++ ret = 0;
++
+ /* Check the ERROR flag */
+ if (flags & BCDC_DCMD_ERROR)
+ ret = le32_to_cpu(msg->status);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+@@ -121,11 +121,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp,
+ else
+ err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
+
+- if (err >= 0)
+- return 0;
+-
+- brcmf_dbg(FIL, "Failed: %s (%d)\n",
+- brcmf_fil_get_errstr((u32)(-err)), err);
++ if (err)
++ brcmf_dbg(FIL, "Failed: %s (%d)\n",
++ brcmf_fil_get_errstr((u32)(-err)), err);
+
+ return err;
+ }
--- /dev/null
+From b69c1df47281ad47bd2037a42b98f5c7115b7fd5 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Mon, 22 Jan 2018 21:46:40 +0100
+Subject: [PATCH] brcmfmac: separate firmware errors from i/o errors
+
+When using the firmware api it can fail simply because firmware does
+not like the request or it fails due to issues in the host interface.
+Currently, there is only a single error code which is confusing. So
+adding a parameter to pass the firmware error separately and in case
+of a firmware error always return -EBADE to user-space.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 ++++++-----
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 16 +++++++++++-----
+ .../net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 10 ++++++----
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h | 14 ++++++++------
+ 4 files changed, 31 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+@@ -165,7 +165,7 @@ static int brcmf_proto_bcdc_cmplt(struct
+
+ static int
+ brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+- void *buf, uint len)
++ void *buf, uint len, int *fwerr)
+ {
+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+ struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+@@ -175,6 +175,7 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf
+
+ brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
+
++ *fwerr = 0;
+ ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
+ if (ret < 0) {
+ brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
+@@ -215,15 +216,14 @@ retry:
+
+ /* Check the ERROR flag */
+ if (flags & BCDC_DCMD_ERROR)
+- ret = le32_to_cpu(msg->status);
+-
++ *fwerr = le32_to_cpu(msg->status);
+ done:
+ return ret;
+ }
+
+ static int
+ brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+- void *buf, uint len)
++ void *buf, uint len, int *fwerr)
+ {
+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
+ struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
+@@ -232,6 +232,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
+
+ brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
+
++ *fwerr = 0;
+ ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
+ if (ret < 0)
+ goto done;
+@@ -255,7 +256,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
+
+ /* Check the ERROR flag */
+ if (flags & BCDC_DCMD_ERROR)
+- ret = le32_to_cpu(msg->status);
++ *fwerr = le32_to_cpu(msg->status);
+
+ done:
+ return ret;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+@@ -107,7 +107,7 @@ static s32
+ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
+ {
+ struct brcmf_pub *drvr = ifp->drvr;
+- s32 err;
++ s32 err, fwerr;
+
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
+ brcmf_err("bus is down. we have nothing to do.\n");
+@@ -117,14 +117,20 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp,
+ if (data != NULL)
+ len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
+ if (set)
+- err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
++ err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
++ data, len, &fwerr);
+ else
+- err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
++ err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
++ data, len, &fwerr);
+
+- if (err)
++ if (err) {
+ brcmf_dbg(FIL, "Failed: %s (%d)\n",
+ brcmf_fil_get_errstr((u32)(-err)), err);
+-
++ } else if (fwerr < 0) {
++ brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
++ brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
++ err = -EBADE;
++ }
+ return err;
+ }
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+@@ -477,7 +477,7 @@ static void brcmf_msgbuf_ioctl_resp_wake
+
+
+ static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
+- uint cmd, void *buf, uint len)
++ uint cmd, void *buf, uint len, int *fwerr)
+ {
+ struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
+ struct sk_buff *skb = NULL;
+@@ -485,6 +485,7 @@ static int brcmf_msgbuf_query_dcmd(struc
+ int err;
+
+ brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);
++ *fwerr = 0;
+ msgbuf->ctl_completed = false;
+ err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);
+ if (err)
+@@ -508,14 +509,15 @@ static int brcmf_msgbuf_query_dcmd(struc
+ }
+ brcmu_pkt_buf_free_skb(skb);
+
+- return msgbuf->ioctl_resp_status;
++ *fwerr = msgbuf->ioctl_resp_status;
++ return 0;
+ }
+
+
+ static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,
+- uint cmd, void *buf, uint len)
++ uint cmd, void *buf, uint len, int *fwerr)
+ {
+- return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len);
++ return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
+ }
+
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+@@ -30,9 +30,9 @@ struct brcmf_proto {
+ 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);
++ void *buf, uint len, int *fwerr);
+ int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
+- uint len);
++ uint len, int *fwerr);
+ int (*tx_queue_data)(struct brcmf_pub *drvr, int ifidx,
+ struct sk_buff *skb);
+ int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset,
+@@ -71,14 +71,16 @@ static inline int brcmf_proto_hdrpull(st
+ 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)
++ uint cmd, void *buf, uint len,
++ int *fwerr)
+ {
+- return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);
++ return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len,fwerr);
+ }
+ static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
+- uint cmd, void *buf, uint len)
++ uint cmd, void *buf, uint len,
++ int *fwerr)
+ {
+- return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
++ return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
+ }
+
+ static inline int brcmf_proto_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
+++ /dev/null
-From 5242a5444e0b6464d7455beb55d936dd192b5e9d Mon Sep 17 00:00:00 2001
-From: Arend Van Spriel <arend.vanspriel@broadcom.com>
-Date: Mon, 22 Jan 2018 21:46:39 +0100
-Subject: [PATCH] brcmfmac: assure bcdc dcmd api does not return value > 0
-
-The protocol layer api defines callbacks for dongle commands.
-Although not really well documented these should only return an
-error code in case of an error, or 0 upon success. In the bcdc
-protocol it can return value above 0 and we carry a fix in the
-caller of the protocol layer api. This patch makes it adhere to
-the intent of the api as described above.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 6 +++++-
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 8 +++-----
- 2 files changed, 8 insertions(+), 6 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-@@ -211,6 +211,8 @@ retry:
- memcpy(buf, info, len);
- }
-
-+ ret = 0;
-+
- /* Check the ERROR flag */
- if (flags & BCDC_DCMD_ERROR)
- ret = le32_to_cpu(msg->status);
-@@ -225,7 +227,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
- {
- struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
- struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
-- int ret = 0;
-+ int ret;
- u32 flags, id;
-
- brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
-@@ -249,6 +251,8 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
- goto done;
- }
-
-+ ret = 0;
-+
- /* Check the ERROR flag */
- if (flags & BCDC_DCMD_ERROR)
- ret = le32_to_cpu(msg->status);
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
-@@ -121,11 +121,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp,
- else
- err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
-
-- if (err >= 0)
-- return 0;
--
-- brcmf_dbg(FIL, "Failed: %s (%d)\n",
-- brcmf_fil_get_errstr((u32)(-err)), err);
-+ if (err)
-+ brcmf_dbg(FIL, "Failed: %s (%d)\n",
-+ brcmf_fil_get_errstr((u32)(-err)), err);
-
- return err;
- }
+++ /dev/null
-From b69c1df47281ad47bd2037a42b98f5c7115b7fd5 Mon Sep 17 00:00:00 2001
-From: Arend Van Spriel <arend.vanspriel@broadcom.com>
-Date: Mon, 22 Jan 2018 21:46:40 +0100
-Subject: [PATCH] brcmfmac: separate firmware errors from i/o errors
-
-When using the firmware api it can fail simply because firmware does
-not like the request or it fails due to issues in the host interface.
-Currently, there is only a single error code which is confusing. So
-adding a parameter to pass the firmware error separately and in case
-of a firmware error always return -EBADE to user-space.
-
-Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
-Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
-Reviewed-by: Franky Lin <franky.lin@broadcom.com>
-Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
-Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 11 ++++++-----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 16 +++++++++++-----
- .../net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 10 ++++++----
- drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h | 14 ++++++++------
- 4 files changed, 31 insertions(+), 20 deletions(-)
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
-@@ -165,7 +165,7 @@ static int brcmf_proto_bcdc_cmplt(struct
-
- static int
- brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-- void *buf, uint len)
-+ void *buf, uint len, int *fwerr)
- {
- struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
- struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
-@@ -175,6 +175,7 @@ brcmf_proto_bcdc_query_dcmd(struct brcmf
-
- brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
-
-+ *fwerr = 0;
- ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
- if (ret < 0) {
- brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
-@@ -215,15 +216,14 @@ retry:
-
- /* Check the ERROR flag */
- if (flags & BCDC_DCMD_ERROR)
-- ret = le32_to_cpu(msg->status);
--
-+ *fwerr = le32_to_cpu(msg->status);
- done:
- return ret;
- }
-
- static int
- brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
-- void *buf, uint len)
-+ void *buf, uint len, int *fwerr)
- {
- struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
- struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
-@@ -232,6 +232,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
-
- brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
-
-+ *fwerr = 0;
- ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
- if (ret < 0)
- goto done;
-@@ -255,7 +256,7 @@ brcmf_proto_bcdc_set_dcmd(struct brcmf_p
-
- /* Check the ERROR flag */
- if (flags & BCDC_DCMD_ERROR)
-- ret = le32_to_cpu(msg->status);
-+ *fwerr = le32_to_cpu(msg->status);
-
- done:
- return ret;
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
-@@ -107,7 +107,7 @@ static s32
- brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
- {
- struct brcmf_pub *drvr = ifp->drvr;
-- s32 err;
-+ s32 err, fwerr;
-
- if (drvr->bus_if->state != BRCMF_BUS_UP) {
- brcmf_err("bus is down. we have nothing to do.\n");
-@@ -117,14 +117,20 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp,
- if (data != NULL)
- len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
- if (set)
-- err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
-+ err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
-+ data, len, &fwerr);
- else
-- err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
-+ err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
-+ data, len, &fwerr);
-
-- if (err)
-+ if (err) {
- brcmf_dbg(FIL, "Failed: %s (%d)\n",
- brcmf_fil_get_errstr((u32)(-err)), err);
--
-+ } else if (fwerr < 0) {
-+ brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
-+ brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
-+ err = -EBADE;
-+ }
- return err;
- }
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
-@@ -477,7 +477,7 @@ static void brcmf_msgbuf_ioctl_resp_wake
-
-
- static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx,
-- uint cmd, void *buf, uint len)
-+ uint cmd, void *buf, uint len, int *fwerr)
- {
- struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
- struct sk_buff *skb = NULL;
-@@ -485,6 +485,7 @@ static int brcmf_msgbuf_query_dcmd(struc
- int err;
-
- brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len);
-+ *fwerr = 0;
- msgbuf->ctl_completed = false;
- err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len);
- if (err)
-@@ -508,14 +509,15 @@ static int brcmf_msgbuf_query_dcmd(struc
- }
- brcmu_pkt_buf_free_skb(skb);
-
-- return msgbuf->ioctl_resp_status;
-+ *fwerr = msgbuf->ioctl_resp_status;
-+ return 0;
- }
-
-
- static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx,
-- uint cmd, void *buf, uint len)
-+ uint cmd, void *buf, uint len, int *fwerr)
- {
-- return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len);
-+ return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
- }
-
-
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
-@@ -30,9 +30,9 @@ struct brcmf_proto {
- 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);
-+ void *buf, uint len, int *fwerr);
- int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
-- uint len);
-+ uint len, int *fwerr);
- int (*tx_queue_data)(struct brcmf_pub *drvr, int ifidx,
- struct sk_buff *skb);
- int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset,
-@@ -71,14 +71,16 @@ static inline int brcmf_proto_hdrpull(st
- 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)
-+ uint cmd, void *buf, uint len,
-+ int *fwerr)
- {
-- return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);
-+ return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len,fwerr);
- }
- static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,
-- uint cmd, void *buf, uint len)
-+ uint cmd, void *buf, uint len,
-+ int *fwerr)
- {
-- return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);
-+ return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len, fwerr);
- }
-
- static inline int brcmf_proto_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
--- /dev/null
+From 933897342d0714ae1c10729cbaeecea0c6178db5 Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Wed, 28 Feb 2018 21:15:19 +0100
+Subject: [PATCH] brcmfmac: add possibility to obtain firmware error
+
+The feature module needs to evaluate the actual firmware error return
+upon a control command. This adds a flag to struct brcmf_if that the
+caller can set. This flag is checked to determine the error code that
+needs to be returned.
+
+Fixes: b69c1df47281 ("brcmfmac: separate firmware errors from i/o errors")
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h | 2 ++
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c | 10 ++++++++++
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 3 +++
+ 3 files changed, 15 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+@@ -181,6 +181,7 @@ enum brcmf_netif_stop_reason {
+ * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
+ * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
+ * @pend_8021x_wait: used for signalling change in count.
++ * @fwil_fwerr: flag indicating fwil layer should return firmware error codes.
+ */
+ struct brcmf_if {
+ struct brcmf_pub *drvr;
+@@ -198,6 +199,7 @@ struct brcmf_if {
+ wait_queue_head_t pend_8021x_wait;
+ struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
+ u8 ipv6addr_idx;
++ bool fwil_fwerr;
+ };
+
+ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+@@ -104,6 +104,9 @@ static void brcmf_feat_iovar_int_get(str
+ u32 data;
+ int err;
+
++ /* we need to know firmware error */
++ ifp->fwil_fwerr = true;
++
+ err = brcmf_fil_iovar_int_get(ifp, name, &data);
+ if (err == 0) {
+ brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
+@@ -112,6 +115,8 @@ static void brcmf_feat_iovar_int_get(str
+ brcmf_dbg(TRACE, "%s feature check failed: %d\n",
+ brcmf_feat_names[id], err);
+ }
++
++ ifp->fwil_fwerr = false;
+ }
+
+ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
+@@ -120,6 +125,9 @@ static void brcmf_feat_iovar_data_set(st
+ {
+ int err;
+
++ /* we need to know firmware error */
++ ifp->fwil_fwerr = true;
++
+ err = brcmf_fil_iovar_data_set(ifp, name, data, len);
+ if (err != -BRCMF_FW_UNSUPPORTED) {
+ brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
+@@ -128,6 +136,8 @@ static void brcmf_feat_iovar_data_set(st
+ brcmf_dbg(TRACE, "%s feature check failed: %d\n",
+ brcmf_feat_names[id], err);
+ }
++
++ ifp->fwil_fwerr = false;
+ }
+
+ #define MAX_CAPS_BUFFER_SIZE 512
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+@@ -131,6 +131,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp,
+ brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
+ err = -EBADE;
+ }
++ if (ifp->fwil_fwerr)
++ return fwerr;
++
+ return err;
+ }
+
--- /dev/null
+From 455f3e76cfc0d893585a5f358b9ddbe9c1e1e53b Mon Sep 17 00:00:00 2001
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Wed, 28 Feb 2018 21:15:20 +0100
+Subject: [PATCH] brcmfmac: fix P2P_DEVICE ethernet address generation
+
+The firmware has a requirement that the P2P_DEVICE address should
+be different from the address of the primary interface. When not
+specified by user-space, the driver generates the MAC address for
+the P2P_DEVICE interface using the MAC address of the primary
+interface and setting the locally administered bit. However, the MAC
+address of the primary interface may already have that bit set causing
+the creation of the P2P_DEVICE interface to fail with -EBUSY. Fix this
+by using a random address instead to determine the P2P_DEVICE address.
+
+Cc: stable@vger.kernel.org # 3.10.y
+Reported-by: Hans de Goede <hdegoede@redhat.com>
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 24 ++++++++++------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+@@ -462,25 +462,23 @@ static int brcmf_p2p_set_firmware(struct
+ * @dev_addr: optional device address.
+ *
+ * P2P needs mac addresses for P2P device and interface. If no device
+- * address it specified, these are derived from the primary net device, ie.
+- * the permanent ethernet address of the device.
++ * address it specified, these are derived from a random ethernet
++ * address.
+ */
+ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
+ {
+- struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+- bool local_admin = false;
++ bool random_addr = false;
+
+- if (!dev_addr || is_zero_ether_addr(dev_addr)) {
+- dev_addr = pri_ifp->mac_addr;
+- local_admin = true;
+- }
++ if (!dev_addr || is_zero_ether_addr(dev_addr))
++ random_addr = true;
+
+- /* Generate the P2P Device Address. This consists of the device's
+- * primary MAC address with the locally administered bit set.
++ /* Generate the P2P Device Address obtaining a random ethernet
++ * address with the locally administered bit set.
+ */
+- memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
+- if (local_admin)
+- p2p->dev_addr[0] |= 0x02;
++ if (random_addr)
++ eth_random_addr(p2p->dev_addr);
++ else
++ memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
+
+ /* Generate the P2P Interface Address. If the discovery and connection
+ * BSSCFGs need to simultaneously co-exist, then this address must be
--- /dev/null
+From 1259055170287a350cad453e9eac139c81609860 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 15 Mar 2018 08:29:09 +0100
+Subject: [PATCH] brcmfmac: drop Inter-Access Point Protocol packets by default
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Testing brcmfmac with more recent firmwares resulted in AP interfaces
+not working in some specific setups. Debugging resulted in discovering
+support for IAPP in Broadcom's firmwares.
+
+Older firmwares were only generating 802.11f frames. Newer ones like:
+1) 10.10 (TOB) (r663589)
+2) 10.10.122.20 (r683106)
+for 4366b1 and 4366c0 respectively seem to also /respect/ 802.11f frames
+in the Tx path by performing a STA disassociation.
+
+This obsoleted standard and its implementation is something that:
+1) Most people don't need / want to use
+2) Can allow local DoS attacks
+3) Breaks AP interfaces in some specific bridge setups
+
+To solve issues it can cause this commit modifies brcmfmac to drop IAPP
+packets. If affects:
+1) Rx path: driver won't be sending these unwanted packets up.
+2) Tx path: driver will reject packets that would trigger STA
+ disassociation perfromed by a firmware (possible local DoS attack).
+
+It appears there are some Broadcom's clients/users who care about this
+feature despite the drawbacks. They can switch it on using a new module
+param.
+
+This change results in only two more comparisons (check for module param
+and check for Ethernet packet length) for 99.9% of packets. Its overhead
+should be very minimal.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ .../wireless/broadcom/brcm80211/brcmfmac/common.c | 5 ++
+ .../wireless/broadcom/brcm80211/brcmfmac/common.h | 1 +
+ .../wireless/broadcom/brcm80211/brcmfmac/core.c | 57 ++++++++++++++++++++++
+ 3 files changed, 63 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+@@ -75,6 +75,10 @@ static int brcmf_roamoff;
+ module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+ MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
+
++static int brcmf_iapp_enable;
++module_param_named(iapp, brcmf_iapp_enable, int, 0);
++MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
++
+ #ifdef DEBUG
+ /* always succeed brcmf_bus_started() */
+ static int brcmf_ignore_probe_fail;
+@@ -441,6 +445,7 @@ struct brcmf_mp_device *brcmf_get_module
+ settings->feature_disable = brcmf_feature_disable;
+ settings->fcmode = brcmf_fcmode;
+ settings->roamoff = !!brcmf_roamoff;
++ settings->iapp = !!brcmf_iapp_enable;
+ #ifdef DEBUG
+ settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
+ #endif
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+@@ -58,6 +58,7 @@ struct brcmf_mp_device {
+ unsigned int feature_disable;
+ int fcmode;
+ bool roamoff;
++ bool iapp;
+ bool ignore_probe_fail;
+ struct brcmfmac_pd_cc *country_codes;
+ union {
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -230,6 +230,37 @@ static void brcmf_netdev_set_multicast_l
+ schedule_work(&ifp->multicast_work);
+ }
+
++/**
++ * brcmf_skb_is_iapp - checks if skb is an IAPP packet
++ *
++ * @skb: skb to check
++ */
++static bool brcmf_skb_is_iapp(struct sk_buff *skb)
++{
++ static const u8 iapp_l2_update_packet[6] __aligned(2) = {
++ 0x00, 0x01, 0xaf, 0x81, 0x01, 0x00,
++ };
++ unsigned char *eth_data;
++#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
++ const u16 *a, *b;
++#endif
++
++ if (skb->len - skb->mac_len != 6 ||
++ !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
++ return false;
++
++ eth_data = skb_mac_header(skb) + ETH_HLEN;
++#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
++ return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) |
++ ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4))));
++#else
++ a = (const u16 *)eth_data;
++ b = (const u16 *)iapp_l2_update_packet;
++
++ return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]));
++#endif
++}
++
+ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+ {
+@@ -250,6 +281,23 @@ static netdev_tx_t brcmf_netdev_start_xm
+ goto done;
+ }
+
++ /* Some recent Broadcom's firmwares disassociate STA when they receive
++ * an 802.11f ADD frame. This behavior can lead to a local DoS security
++ * issue. Attacker may trigger disassociation of any STA by sending a
++ * proper Ethernet frame to the wireless interface.
++ *
++ * Moreover this feature may break AP interfaces in some specific
++ * setups. This applies e.g. to the bridge with hairpin mode enabled and
++ * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware
++ * will get passed back to the wireless interface and cause immediate
++ * disassociation of a just-connected STA.
++ */
++ if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
++ dev_kfree_skb(skb);
++ ret = -EINVAL;
++ goto done;
++ }
++
+ /* Make sure there's enough writeable headroom */
+ if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
+ head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
+@@ -325,6 +373,15 @@ void brcmf_txflowblock_if(struct brcmf_i
+
+ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
+ {
++ /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
++ * STA connects to the AP interface. This is an obsoleted standard most
++ * users don't use, so don't pass these frames up unless requested.
++ */
++ if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
++ brcmu_pkt_buf_free_skb(skb);
++ return;
++ }
++
+ if (skb->pkt_type == PACKET_MULTICAST)
+ ifp->ndev->stats.multicast++;
+
--- /dev/null
+From 9b9322db5c5a1917a66c71fe47c3848a9a31227e Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <stefan.wahren@i2se.com>
+Date: Wed, 14 Mar 2018 20:02:59 +0100
+Subject: [PATCH] brcmfmac: Fix check for ISO3166 code
+
+The commit "regulatory: add NUL to request alpha2" increases the length of
+alpha2 to 3. This causes a regression on brcmfmac, because
+brcmf_cfg80211_reg_notifier() expect valid ISO3166 codes in the complete
+array. So fix this accordingly.
+
+Fixes: 657308f73e67 ("regulatory: add NUL to request alpha2")
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+Acked-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -6803,7 +6803,7 @@ static void brcmf_cfg80211_reg_notifier(
+ return;
+
+ /* ignore non-ISO3166 country codes */
+- for (i = 0; i < sizeof(req->alpha2); i++)
++ for (i = 0; i < 2; i++)
+ if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
+ brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
+ req->alpha2[0], req->alpha2[1]);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1238,6 +1238,7 @@ int __init brcmf_core_init(void)
+@@ -1295,6 +1295,7 @@ int __init brcmf_core_init(void)
{
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;