From 748db392fcbd5c24e91a3cfed0802c95c9585a1c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 7 Mar 2016 22:37:09 +0000 Subject: [PATCH] mac80211: backport brcmfmac patchset with driver setting concept MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This prepares brcmfmac for better country handling and fixes BCM4360 support which was always failing with: [ 13.249195] brcmfmac: brcmf_pcie_download_fw_nvram: FW failed to initialize Signed-off-by: Rafał Miłecki SVN-Revision: 48959 --- ...function-name-for-brcmf_cfg80211_wai.patch | 99 +++ ...-brcmfmac-Limit-memory-allocs-to-64K.patch | 127 +++ ...or-wowl-support-before-enumerating-f.patch | 29 + ...re-country-code-using-device-specifi.patch | 214 +++++ ...Add-length-checks-on-firmware-events.patch | 283 +++++++ ...ghbor-discovery-offload-ip-address-t.patch | 333 ++++++++ ...heck-return-for-ARP-ip-setting-iovar.patch | 38 + ...ice-memsize-config-from-fw-if-define.patch | 73 ++ ...1-window-size-as-provided-by-pci-sub.patch | 58 ++ ...add-support-for-the-PCIE-4366c0-chip.patch | 34 + ...11-brcmfmac-remove-pcie-gen1-support.patch | 221 ++++++ ...cmfmac-increase-timeout-for-tx-eapol.patch | 30 + ...-move-module-init-and-exit-to-common.patch | 135 ++++ ...dd-wowl-gtk-rekeying-offload-support.patch | 260 +++++++ ...atform-data-retrieval-code-to-common.patch | 385 +++++++++ ...P-and-ND-offload-enabled-during-WOWL.patch | 69 ++ ...brcmfmac-switch-to-new-platform-data.patch | 734 ++++++++++++++++++ ...-platform-data-and-module-paramaters.patch | 607 +++++++++++++++ ...fmac-integrate-add_keyext-in-add_key.patch | 227 ++++++ ....11w-management-frame-protection-sup.patch | 509 ++++++++++++ ...-register-wiphy-s-during-module_init.patch | 4 +- ...und-bug-with-some-inconsistent-BSSes.patch | 2 +- 22 files changed, 4468 insertions(+), 3 deletions(-) create mode 100644 package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch create mode 100644 package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch create mode 100644 package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch create mode 100644 package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch create mode 100644 package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch create mode 100644 package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch create mode 100644 package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch create mode 100644 package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch create mode 100644 package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch create mode 100644 package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch create mode 100644 package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch create mode 100644 package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch create mode 100644 package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch create mode 100644 package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch create mode 100644 package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch create mode 100644 package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch create mode 100644 package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch create mode 100644 package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch create mode 100644 package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch create mode 100644 package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch diff --git a/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch b/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch new file mode 100644 index 0000000000..e3427de732 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0001-brcmfmac-change-function-name-for-brcmf_cfg80211_wai.patch @@ -0,0 +1,99 @@ +From: Arend van Spriel +Date: Wed, 17 Feb 2016 11:26:50 +0100 +Subject: [PATCH] brcmfmac: change function name for + brcmf_cfg80211_wait_vif_event_timeout() + +Dropping the '_timeout' from the function name as the fact that a timeout +value is passed makes it obvious a timeout is used. Also helps to keep code +lines a bit shorter and easier to stick to 80 char boundary. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -564,8 +564,8 @@ struct wireless_dev *brcmf_ap_add_vif(st + } + + /* wait for firmware event */ +- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, +- BRCMF_VIF_EVENT_TIMEOUT); ++ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD, ++ BRCMF_VIF_EVENT_TIMEOUT); + brcmf_cfg80211_arm_vif_event(cfg, NULL); + if (!err) { + brcmf_err("timeout occurred\n"); +@@ -6395,8 +6395,9 @@ bool brcmf_cfg80211_vif_event_armed(stru + + return armed; + } +-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, +- u8 action, ulong timeout) ++ ++int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, ++ u8 action, ulong timeout) + { + struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -402,8 +402,8 @@ bool brcmf_get_vif_state_any(struct brcm + void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif); + bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); +-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, +- u8 action, ulong timeout); ++int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg, ++ u8 action, ulong timeout); + s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp, bool aborted, + bool fw_abort); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1988,8 +1988,8 @@ int brcmf_p2p_ifchange(struct brcmf_cfg8 + brcmf_cfg80211_arm_vif_event(cfg, NULL); + return err; + } +- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, +- BRCMF_VIF_EVENT_TIMEOUT); ++ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE, ++ BRCMF_VIF_EVENT_TIMEOUT); + brcmf_cfg80211_arm_vif_event(cfg, NULL); + if (!err) { + brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); +@@ -2090,8 +2090,8 @@ static struct wireless_dev *brcmf_p2p_cr + } + + /* wait for firmware event */ +- err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD, +- BRCMF_VIF_EVENT_TIMEOUT); ++ err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD, ++ BRCMF_VIF_EVENT_TIMEOUT); + brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL); + brcmf_fweh_p2pdev_setup(pri_ifp, false); + if (!err) { +@@ -2180,8 +2180,8 @@ struct wireless_dev *brcmf_p2p_add_vif(s + } + + /* wait for firmware event */ +- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, +- BRCMF_VIF_EVENT_TIMEOUT); ++ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD, ++ BRCMF_VIF_EVENT_TIMEOUT); + brcmf_cfg80211_arm_vif_event(cfg, NULL); + if (!err) { + brcmf_err("timeout occurred\n"); +@@ -2274,8 +2274,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiph + } + if (!err) { + /* wait for firmware event */ +- err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, +- BRCMF_VIF_EVENT_TIMEOUT); ++ err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL, ++ BRCMF_VIF_EVENT_TIMEOUT); + if (!err) + err = -EIO; + else diff --git a/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch b/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch new file mode 100644 index 0000000000..9c336f774f --- /dev/null +++ b/package/kernel/mac80211/patches/344-0002-brcmfmac-Limit-memory-allocs-to-64K.patch @@ -0,0 +1,127 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:51 +0100 +Subject: [PATCH] brcmfmac: Limit memory allocs to <64K + +Some systems have problems with allocating memory allocation larger +then 64K. Often on unload/load or suspend/resume a failure is +reported: Could not allocate wiphy device. This patch makes the +escan intermediate storage buf dynamically allocated, and smaller +than 64K. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -1125,7 +1125,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy + + /* Arm scan timeout timer */ + mod_timer(&cfg->escan_timeout, jiffies + +- WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); ++ BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); + + return 0; + +@@ -3020,7 +3020,7 @@ brcmf_cfg80211_escan_handler(struct brcm + + list = (struct brcmf_scan_results *) + cfg->escan_info.escan_buf; +- if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) { ++ if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) { + brcmf_err("Buffer is too small: ignoring\n"); + goto exit; + } +@@ -3033,8 +3033,8 @@ brcmf_cfg80211_escan_handler(struct brcm + bss_info_le)) + goto exit; + } +- memcpy(&(cfg->escan_info.escan_buf[list->buflen]), +- bss_info_le, bi_length); ++ memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le, ++ bi_length); + list->version = le32_to_cpu(bss_info_le->version); + list->buflen += bi_length; + list->count++; +@@ -5402,14 +5402,14 @@ static void brcmf_deinit_priv_mem(struct + { + kfree(cfg->conf); + cfg->conf = NULL; +- kfree(cfg->escan_ioctl_buf); +- cfg->escan_ioctl_buf = NULL; + kfree(cfg->extra_buf); + cfg->extra_buf = NULL; + kfree(cfg->wowl.nd); + cfg->wowl.nd = NULL; + kfree(cfg->wowl.nd_info); + cfg->wowl.nd_info = NULL; ++ kfree(cfg->escan_info.escan_buf); ++ cfg->escan_info.escan_buf = NULL; + } + + static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg) +@@ -5417,9 +5417,6 @@ static s32 brcmf_init_priv_mem(struct br + cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL); + if (!cfg->conf) + goto init_priv_mem_out; +- cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); +- if (!cfg->escan_ioctl_buf) +- goto init_priv_mem_out; + cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!cfg->extra_buf) + goto init_priv_mem_out; +@@ -5431,6 +5428,9 @@ static s32 brcmf_init_priv_mem(struct br + GFP_KERNEL); + if (!cfg->wowl.nd_info) + goto init_priv_mem_out; ++ cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL); ++ if (!cfg->escan_info.escan_buf) ++ goto init_priv_mem_out; + + return 0; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -28,8 +28,11 @@ + #define WL_ROAM_TRIGGER_LEVEL -75 + #define WL_ROAM_DELTA 20 + +-#define WL_ESCAN_BUF_SIZE (1024 * 64) +-#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */ ++/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be ++ * problematic on some systems and should be avoided. ++ */ ++#define BRCMF_ESCAN_BUF_SIZE 65000 ++#define BRCMF_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */ + + #define WL_ESCAN_ACTION_START 1 + #define WL_ESCAN_ACTION_CONTINUE 2 +@@ -205,7 +208,7 @@ enum wl_escan_state { + + struct escan_info { + u32 escan_state; +- u8 escan_buf[WL_ESCAN_BUF_SIZE]; ++ u8 *escan_buf; + struct wiphy *wiphy; + struct brcmf_if *ifp; + s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, +@@ -278,7 +281,6 @@ struct brcmf_cfg80211_wowl { + * @escan_info: escan information. + * @escan_timeout: Timer for catch scan timeout. + * @escan_timeout_work: scan timeout worker. +- * @escan_ioctl_buf: dongle command buffer for escan commands. + * @vif_list: linked list of vif instances. + * @vif_cnt: number of vif instances. + * @vif_event: vif event signalling. +@@ -309,7 +311,6 @@ struct brcmf_cfg80211_info { + struct escan_info escan_info; + struct timer_list escan_timeout; + struct work_struct escan_timeout_work; +- u8 *escan_ioctl_buf; + struct list_head vif_list; + struct brcmf_cfg80211_vif_event vif_event; + struct completion vif_disabled; diff --git a/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch b/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch new file mode 100644 index 0000000000..ee3d9f37a8 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0003-brcmfmac-check-for-wowl-support-before-enumerating-f.patch @@ -0,0 +1,29 @@ +From: Franky Lin +Date: Wed, 17 Feb 2016 11:26:52 +0100 +Subject: [PATCH] brcmfmac: check for wowl support before enumerating feature + flag + +In some cases wiphy->wowlan could be NULL if firmware doesn't have the +support. Driver should check for support before walking down the feature +flags. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Hante Meuleman +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6594,7 +6594,8 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) { + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; + #ifdef CONFIG_PM +- if (wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT) ++ if (wiphy->wowlan && ++ wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT) + wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR; + #endif + } diff --git a/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch b/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch new file mode 100644 index 0000000000..c52cac87b9 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0004-brcmfmac-Configure-country-code-using-device-specifi.patch @@ -0,0 +1,214 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:53 +0100 +Subject: [PATCH] brcmfmac: Configure country code using device specific + settings + +Country code configuration in a device is a device specific +operation. For this the country code as specified by reg notifier +(iso3166 alpha2) needs to be translated to a device specific +country locale and revision number. This patch adds this +translation and puts a placeholder in the device specific settings +where the translation table can be stored. Additional patches will +be needed to read these tables from for example device platform +data. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6405,28 +6405,85 @@ int brcmf_cfg80211_wait_vif_event(struct + vif_event_equals(event, action), timeout); + } + ++static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], ++ struct brcmf_fil_country_le *ccreq) ++{ ++ struct cc_translate *country_codes; ++ struct cc_entry *cc; ++ s32 found_index; ++ int i; ++ ++ country_codes = drvr->settings->country_codes; ++ if (!country_codes) { ++ brcmf_dbg(TRACE, "No country codes configured for device\n"); ++ return -EINVAL; ++ } ++ ++ if ((alpha2[0] == ccreq->country_abbrev[0]) && ++ (alpha2[1] == ccreq->country_abbrev[1])) { ++ brcmf_dbg(TRACE, "Country code already set\n"); ++ return -EAGAIN; ++ } ++ ++ found_index = -1; ++ for (i = 0; i < country_codes->table_size; i++) { ++ cc = &country_codes->table[i]; ++ if ((cc->iso3166[0] == '\0') && (found_index == -1)) ++ found_index = i; ++ if ((cc->iso3166[0] == alpha2[0]) && ++ (cc->iso3166[1] == alpha2[1])) { ++ found_index = i; ++ break; ++ } ++ } ++ if (found_index == -1) { ++ brcmf_dbg(TRACE, "No country code match found\n"); ++ return -EINVAL; ++ } ++ memset(ccreq, 0, sizeof(*ccreq)); ++ ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev); ++ memcpy(ccreq->ccode, country_codes->table[found_index].cc, ++ BRCMF_COUNTRY_BUF_SZ); ++ ccreq->country_abbrev[0] = alpha2[0]; ++ ccreq->country_abbrev[1] = alpha2[1]; ++ ccreq->country_abbrev[2] = 0; ++ ++ return 0; ++} ++ + static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) + { + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_fil_country_le ccreq; ++ s32 err; + int i; + +- brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator, +- req->alpha2[0], req->alpha2[1]); +- + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { +- brcmf_err("not a ISO3166 code\n"); ++ brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", ++ req->alpha2[0], req->alpha2[1]); + return; + } +- memset(&ccreq, 0, sizeof(ccreq)); +- ccreq.rev = cpu_to_le32(-1); +- memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2)); +- if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) { +- brcmf_err("firmware rejected country setting\n"); ++ ++ brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator, ++ req->alpha2[0], req->alpha2[1]); ++ ++ err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq)); ++ if (err) { ++ brcmf_err("Country code iovar returned err = %d\n", err); ++ return; ++ } ++ ++ err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq); ++ if (err) ++ return; ++ ++ err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); ++ if (err) { ++ brcmf_err("Firmware rejected country setting\n"); + return; + } + brcmf_setup_wiphybands(wiphy); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -230,10 +230,8 @@ void brcmf_mp_attach(void) + int brcmf_mp_device_attach(struct brcmf_pub *drvr) + { + drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); +- if (!drvr->settings) { +- brcmf_err("Failed to alloca storage space for settings\n"); ++ if (!drvr->settings) + return -ENOMEM; +- } + + drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz; + drvr->settings->p2p_enable = !!brcmf_p2p_enable; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -15,6 +15,8 @@ + #ifndef BRCMFMAC_COMMON_H + #define BRCMFMAC_COMMON_H + ++#include "fwil_types.h" ++ + extern const u8 ALLFFMAC[ETH_ALEN]; + + #define BRCMF_FW_ALTPATH_LEN 256 +@@ -39,6 +41,33 @@ struct brcmf_mp_global_t { + extern struct brcmf_mp_global_t brcmf_mp_global; + + /** ++ * struct cc_entry - Struct for translating user space country code (iso3166) to ++ * firmware country code and revision. ++ * ++ * @iso3166: iso3166 alpha 2 country code string. ++ * @cc: firmware country code string. ++ * @rev: firmware country code revision. ++ */ ++struct cc_entry { ++ char iso3166[BRCMF_COUNTRY_BUF_SZ]; ++ char cc[BRCMF_COUNTRY_BUF_SZ]; ++ s32 rev; ++}; ++ ++/** ++ * struct cc_translate - Struct for translating country codes as set by user ++ * space to a country code and rev which can be used by ++ * firmware. ++ * ++ * @table_size: number of entries in table (> 0) ++ * @table: dynamic array of 1 or more elements with translation information. ++ */ ++struct cc_translate { ++ int table_size; ++ struct cc_entry table[0]; ++}; ++ ++/** + * struct brcmf_mp_device - Device module paramaters. + * + * @sdiod_txglomsz: SDIO txglom size. +@@ -47,6 +76,7 @@ extern struct brcmf_mp_global_t brcmf_mp + * @feature_disable: Feature_disable bitmask. + * @fcmode: FWS flow control. + * @roamoff: Firmware roaming off? ++ * @country_codes: If available, pointer to struct for translating country codes + */ + struct brcmf_mp_device { + int sdiod_txglomsz; +@@ -56,6 +86,7 @@ struct brcmf_mp_device { + int fcmode; + bool roamoff; + bool ignore_probe_fail; ++ struct cc_translate *country_codes; + }; + + void brcmf_mp_attach(void); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -134,6 +134,8 @@ + #define BRCMF_PFN_MAC_OUI_ONLY BIT(0) + #define BRCMF_PFN_SET_MAC_UNASSOC BIT(1) + ++#define BRCMF_MCSSET_LEN 16 ++ + /* join preference types for join_pref iovar */ + enum brcmf_join_pref_types { + BRCMF_JOIN_PREF_RSSI = 1, +@@ -279,7 +281,7 @@ struct brcmf_bss_info_le { + __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ + u8 flags; /* flags */ + u8 reserved[3]; /* Reserved for expansion of BSS properties */ +- u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ u8 basic_mcs[BRCMF_MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + __le16 ie_offset; /* offset at which IEs start, from beginning */ + __le32 ie_length; /* byte length of Information Elements */ diff --git a/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch b/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch new file mode 100644 index 0000000000..3e2e3503b6 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0005-brcmfmac-Add-length-checks-on-firmware-events.patch @@ -0,0 +1,283 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:54 +0100 +Subject: [PATCH] brcmfmac: Add length checks on firmware events + +Add additional length checks on firmware events to create more +robust code. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Lei Zhang +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -3092,6 +3092,11 @@ brcmf_notify_sched_scan_results(struct b + + brcmf_dbg(SCAN, "Enter\n"); + ++ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + if (e->event_code == BRCMF_E_PFN_NET_LOST) { + brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n"); + return 0; +@@ -3415,6 +3420,11 @@ brcmf_wowl_nd_results(struct brcmf_if *i + + brcmf_dbg(SCAN, "Enter\n"); + ++ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + pfn_result = (struct brcmf_pno_scanresults_le *)data; + + if (e->event_code == BRCMF_E_PFN_NET_LOST) { +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +@@ -26,50 +26,6 @@ + #include "fwil.h" + + /** +- * struct brcm_ethhdr - broadcom specific ether header. +- * +- * @subtype: subtype for this packet. +- * @length: TODO: length of appended data. +- * @version: version indication. +- * @oui: OUI of this packet. +- * @usr_subtype: subtype for this OUI. +- */ +-struct brcm_ethhdr { +- __be16 subtype; +- __be16 length; +- u8 version; +- u8 oui[3]; +- __be16 usr_subtype; +-} __packed; +- +-struct brcmf_event_msg_be { +- __be16 version; +- __be16 flags; +- __be32 event_type; +- __be32 status; +- __be32 reason; +- __be32 auth_type; +- __be32 datalen; +- u8 addr[ETH_ALEN]; +- char ifname[IFNAMSIZ]; +- u8 ifidx; +- u8 bsscfgidx; +-} __packed; +- +-/** +- * struct brcmf_event - contents of broadcom event packet. +- * +- * @eth: standard ether header. +- * @hdr: broadcom specific ether header. +- * @msg: common part of the actual event message. +- */ +-struct brcmf_event { +- struct ethhdr eth; +- struct brcm_ethhdr hdr; +- struct brcmf_event_msg_be msg; +-} __packed; +- +-/** + * struct brcmf_fweh_queue_item - event item on event queue. + * + * @q: list element for queuing. +@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item { + u8 ifidx; + u8 ifaddr[ETH_ALEN]; + struct brcmf_event_msg_be emsg; ++ u32 datalen; + u8 data[0]; + }; + +@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(stru + brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, + min_t(u32, emsg.datalen, 64), + "event payload, len=%d\n", emsg.datalen); ++ if (emsg.datalen > event->datalen) { ++ brcmf_err("event invalid length header=%d, msg=%d\n", ++ event->datalen, emsg.datalen); ++ goto event_free; ++ } + + /* special handling of interface event */ + if (event->code == BRCMF_E_IF) { +@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct br + * dispatch the event to a registered handler (using worker). + */ + void brcmf_fweh_process_event(struct brcmf_pub *drvr, +- struct brcmf_event *event_packet) ++ struct brcmf_event *event_packet, ++ u32 packet_len) + { + enum brcmf_fweh_event_code code; + struct brcmf_fweh_info *fweh = &drvr->fweh; +@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brc + if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + return; + ++ if (datalen > BRCMF_DCMD_MAXLEN) ++ return; ++ + if (in_interrupt()) + alloc_flag = GFP_ATOMIC; + +@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brc + /* use memcpy to get aligned event message */ + memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); + memcpy(event->data, data, datalen); ++ event->datalen = datalen; + memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); + + brcmf_fweh_queue_event(fweh, event); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +@@ -27,7 +27,6 @@ + struct brcmf_pub; + struct brcmf_if; + struct brcmf_cfg80211_info; +-struct brcmf_event; + + /* list of firmware events */ + #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ +@@ -180,13 +179,55 @@ enum brcmf_fweh_event_code { + /** + * definitions for event packet validation. + */ +-#define BRCMF_EVENT_OUI_OFFSET 19 +-#define BRCM_OUI "\x00\x10\x18" +-#define DOT11_OUI_LEN 3 +-#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BRCM_OUI "\x00\x10\x18" ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 + + + /** ++ * struct brcm_ethhdr - broadcom specific ether header. ++ * ++ * @subtype: subtype for this packet. ++ * @length: TODO: length of appended data. ++ * @version: version indication. ++ * @oui: OUI of this packet. ++ * @usr_subtype: subtype for this OUI. ++ */ ++struct brcm_ethhdr { ++ __be16 subtype; ++ __be16 length; ++ u8 version; ++ u8 oui[3]; ++ __be16 usr_subtype; ++} __packed; ++ ++struct brcmf_event_msg_be { ++ __be16 version; ++ __be16 flags; ++ __be32 event_type; ++ __be32 status; ++ __be32 reason; ++ __be32 auth_type; ++ __be32 datalen; ++ u8 addr[ETH_ALEN]; ++ char ifname[IFNAMSIZ]; ++ u8 ifidx; ++ u8 bsscfgidx; ++} __packed; ++ ++/** ++ * struct brcmf_event - contents of broadcom event packet. ++ * ++ * @eth: standard ether header. ++ * @hdr: broadcom specific ether header. ++ * @msg: common part of the actual event message. ++ */ ++struct brcmf_event { ++ struct ethhdr eth; ++ struct brcm_ethhdr hdr; ++ struct brcmf_event_msg_be msg; ++} __packed; ++ ++/** + * struct brcmf_event_msg - firmware event message. + * + * @version: version information. +@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_ + enum brcmf_fweh_event_code code); + int brcmf_fweh_activate_events(struct brcmf_if *ifp); + void brcmf_fweh_process_event(struct brcmf_pub *drvr, +- struct brcmf_event *event_packet); ++ struct brcmf_event *event_packet, ++ u32 packet_len); + void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing); + + static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, + struct sk_buff *skb) + { + struct brcmf_event *event_packet; +- u8 *data; + u16 usr_stype; + + /* only process events when protocol matches */ + if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) + return; + ++ if ((skb->len + ETH_HLEN) < sizeof(*event_packet)) ++ return; ++ + /* check for BRCM oui match */ + event_packet = (struct brcmf_event *)skb_mac_header(skb); +- data = (u8 *)event_packet; +- data += BRCMF_EVENT_OUI_OFFSET; +- if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN)) ++ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0], ++ sizeof(event_packet->hdr.oui))) + return; + + /* final match on usr_subtype */ +- data += DOT11_OUI_LEN; +- usr_stype = get_unaligned_be16(data); ++ usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype); + if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) + return; + +- brcmf_fweh_process_event(drvr, event_packet); ++ brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN); + } + + #endif /* FWEH_H_ */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(str + u16 mgmt_type; + u8 action; + ++ if (e->datalen < sizeof(*rxframe)) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + ch.chspec = be16_to_cpu(rxframe->chanspec); + cfg->d11inf.decchspec(&ch); + /* Check if wpa_supplicant has registered for this frame */ +@@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere + brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, + e->reason); + ++ if (e->datalen < sizeof(*rxframe)) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + ch.chspec = be16_to_cpu(rxframe->chanspec); + cfg->d11inf.decchspec(&ch); + diff --git a/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch b/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch new file mode 100644 index 0000000000..888ad5b050 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch @@ -0,0 +1,333 @@ +From: Franky Lin +Date: Wed, 17 Feb 2016 11:26:55 +0100 +Subject: [PATCH] brcmfmac: add neighbor discovery offload ip address table + configuration + +Configure ipv6 address for neighbor discovery offload ip table in +firmware obtained through ipv6 address notification callback. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp, + } + + static s32 +-brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) ++brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable) + { + s32 err; + u32 mode; +@@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf + enable, mode); + } + ++ err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable); ++ if (err) { ++ brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n", ++ enable, err); ++ err = 0; ++ } else ++ brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n", ++ enable, mode); ++ + return err; + } + +@@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct + brcmf_report_wowl_wakeind(wiphy, ifp); + brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); + brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, + cfg->wowl.pre_pmmode); + cfg->wowl.active = false; +@@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct + + brcmf_dbg(TRACE, "Suspend, wowl config.\n"); + +- brcmf_configure_arp_offload(ifp, false); ++ brcmf_configure_arp_nd_offload(ifp, false); + brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); + +@@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + + if (!mbss) { + brcmf_set_mpc(ifp, 0); +- brcmf_configure_arp_offload(ifp, false); ++ brcmf_configure_arp_nd_offload(ifp, false); + } + + /* find the RSN_IE */ +@@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi + exit: + if ((err) && (!mbss)) { + brcmf_set_mpc(ifp, 1); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + } + return err; + } +@@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct + brcmf_err("bss_enable config failed %d\n", err); + } + brcmf_set_mpc(ifp, 1); +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + brcmf_net_setcarrier(ifp, false); + +@@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct br + if (err) + goto default_conf_out; + +- brcmf_configure_arp_offload(ifp, true); ++ brcmf_configure_arp_nd_offload(ifp, true); + + cfg->dongle_up = true; + default_conf_out: +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + +@@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struc + } + } + ++#if IS_ENABLED(CONFIG_IPV6) ++static void _brcmf_update_ndtable(struct work_struct *work) ++{ ++ struct brcmf_if *ifp; ++ int i, ret; ++ ++ ifp = container_of(work, struct brcmf_if, ndoffload_work); ++ ++ /* clear the table in firmware */ ++ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0); ++ if (ret) { ++ brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret); ++ return; ++ } ++ ++ for (i = 0; i < ifp->ipv6addr_idx; i++) { ++ ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip", ++ &ifp->ipv6_addr_tbl[i], ++ sizeof(struct in6_addr)); ++ if (ret) ++ brcmf_err("add nd ip err %d\n", ret); ++ } ++} ++#else ++static void _brcmf_update_ndtable(struct work_struct *work) ++{ ++} ++#endif ++ + static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) + { + struct brcmf_if *ifp = netdev_priv(ndev); +@@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *if + + INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); ++ INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable); + + if (rtnl_locked) + err = register_netdevice(ndev); +@@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pu + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + cancel_work_sync(&ifp->setmacaddr_work); + cancel_work_sync(&ifp->multicast_work); ++ cancel_work_sync(&ifp->ndoffload_work); + } + brcmf_net_detach(ifp->ndev); + } else { +@@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct + } + #endif + ++#if IS_ENABLED(CONFIG_IPV6) ++static int brcmf_inet6addr_changed(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub, ++ inet6addr_notifier); ++ struct inet6_ifaddr *ifa = data; ++ struct brcmf_if *ifp; ++ int i; ++ struct in6_addr *table; ++ ++ /* Only handle primary interface */ ++ ifp = drvr->iflist[0]; ++ if (!ifp) ++ return NOTIFY_DONE; ++ if (ifp->ndev != ifa->idev->dev) ++ return NOTIFY_DONE; ++ ++ table = ifp->ipv6_addr_tbl; ++ for (i = 0; i < NDOL_MAX_ENTRIES; i++) ++ if (ipv6_addr_equal(&ifa->addr, &table[i])) ++ break; ++ ++ switch (action) { ++ case NETDEV_UP: ++ if (i == NDOL_MAX_ENTRIES) { ++ if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) { ++ table[ifp->ipv6addr_idx++] = ifa->addr; ++ } else { ++ for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++) ++ table[i] = table[i + 1]; ++ table[NDOL_MAX_ENTRIES - 1] = ifa->addr; ++ } ++ } ++ break; ++ case NETDEV_DOWN: ++ if (i < NDOL_MAX_ENTRIES) ++ for (; i < ifp->ipv6addr_idx; i++) ++ table[i] = table[i + 1]; ++ break; ++ default: ++ break; ++ } ++ ++ schedule_work(&ifp->ndoffload_work); ++ ++ return NOTIFY_OK; ++} ++#endif ++ + int brcmf_attach(struct device *dev) + { + struct brcmf_pub *drvr = NULL; +@@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev) + #ifdef CONFIG_INET + drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed; + ret = register_inetaddr_notifier(&drvr->inetaddr_notifier); ++ if (ret) ++ goto fail; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed; ++ ret = register_inet6addr_notifier(&drvr->inet6addr_notifier); ++ if (ret) { ++ unregister_inetaddr_notifier(&drvr->inetaddr_notifier); ++ goto fail; ++ } + #endif ++#endif /* CONFIG_INET */ ++ ++ return 0; + + fail: +- if (ret < 0) { +- brcmf_err("failed: %d\n", ret); +- if (drvr->config) { +- brcmf_cfg80211_detach(drvr->config); +- drvr->config = NULL; +- } +- if (drvr->fws) { +- brcmf_fws_del_interface(ifp); +- brcmf_fws_deinit(drvr); +- } +- if (ifp) +- brcmf_net_detach(ifp->ndev); +- if (p2p_ifp) +- brcmf_net_detach(p2p_ifp->ndev); +- drvr->iflist[0] = NULL; +- drvr->iflist[1] = NULL; +- if (brcmf_ignoring_probe_fail(drvr)) +- ret = 0; +- return ret; ++ brcmf_err("failed: %d\n", ret); ++ if (drvr->config) { ++ brcmf_cfg80211_detach(drvr->config); ++ drvr->config = NULL; ++ } ++ if (drvr->fws) { ++ brcmf_fws_del_interface(ifp); ++ brcmf_fws_deinit(drvr); + } +- return 0; ++ if (ifp) ++ brcmf_net_detach(ifp->ndev); ++ if (p2p_ifp) ++ brcmf_net_detach(p2p_ifp->ndev); ++ drvr->iflist[0] = NULL; ++ drvr->iflist[1] = NULL; ++ if (brcmf_ignoring_probe_fail(drvr)) ++ ret = 0; ++ ++ return ret; + } + + void brcmf_bus_add_txhdrlen(struct device *dev, uint len) +@@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev) + unregister_inetaddr_notifier(&drvr->inetaddr_notifier); + #endif + ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&drvr->inet6addr_notifier); ++#endif ++ + /* stop firmware event handling */ + brcmf_fweh_detach(drvr); + if (drvr->config) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -48,6 +48,8 @@ + */ + #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 + ++#define NDOL_MAX_ENTRIES 8 ++ + /** + * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info + * +@@ -143,6 +145,7 @@ struct brcmf_pub { + #endif + + struct notifier_block inetaddr_notifier; ++ struct notifier_block inet6addr_notifier; + struct brcmf_mp_device *settings; + }; + +@@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason { + * @stats: interface specific network statistics. + * @setmacaddr_work: worker object for setting mac address. + * @multicast_work: worker object for multicast provisioning. ++ * @ndoffload_work: worker object for neighbor discovery offload configuration. + * @fws_desc: interface specific firmware-signalling descriptor. + * @ifidx: interface index in device firmware. + * @bsscfgidx: index of bss associated with this interface. +@@ -191,6 +195,7 @@ struct brcmf_if { + struct net_device_stats stats; + struct work_struct setmacaddr_work; + struct work_struct multicast_work; ++ struct work_struct ndoffload_work; + struct brcmf_fws_mac_descriptor *fws_desc; + int ifidx; + s32 bsscfgidx; +@@ -199,6 +204,8 @@ struct brcmf_if { + spinlock_t netif_stop_lock; + atomic_t pend_8021x_cnt; + wait_queue_head_t pend_8021x_wait; ++ struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES]; ++ u8 ipv6addr_idx; + }; + + struct brcmf_skb_reorder_data { diff --git a/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch b/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch new file mode 100644 index 0000000000..68de8ed2a2 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0007-brcmfmac-check-return-for-ARP-ip-setting-iovar.patch @@ -0,0 +1,38 @@ +From: Franky Lin +Date: Wed, 17 Feb 2016 11:26:56 +0100 +Subject: [PATCH] brcmfmac: check return for ARP ip setting iovar + +The return value of iovar set function should be saved and checked. + +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Hante Meuleman +Signed-off-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1039,14 +1039,14 @@ static int brcmf_inetaddr_changed(struct + return NOTIFY_OK; + } + for (i = 0; i < ARPOL_MAX_ENTRIES; i++) { +- if (addr_table[i] != 0) { +- brcmf_fil_iovar_data_set(ifp, +- "arp_hostip", &addr_table[i], +- sizeof(addr_table[i])); +- if (ret) +- brcmf_err("add arp ip err %d\n", +- ret); +- } ++ if (addr_table[i] == 0) ++ continue; ++ ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip", ++ &addr_table[i], ++ sizeof(addr_table[i])); ++ if (ret) ++ brcmf_err("add arp ip err %d\n", ++ ret); + } + } + break; diff --git a/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch b/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch new file mode 100644 index 0000000000..3de0f64d56 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0008-brcmfmac-use-device-memsize-config-from-fw-if-define.patch @@ -0,0 +1,73 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:57 +0100 +Subject: [PATCH] brcmfmac: use device memsize config from fw if defined + +Newer type pcie devices have memory which get shared between fw and +hw. The division of this memory is done firmware compile time. As a +result the ramsize as used by driver needs to be adjusted for this. +This is done by reading the memory size from the firmware. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brc + #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4 + #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3 + ++/* Magic number at a magic location to find RAM size */ ++#define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */ ++#define BRCMF_RAMSIZE_OFFSET 0x6c ++ + + struct brcmf_pcie_console { + u32 base_addr; +@@ -1412,6 +1416,28 @@ static const struct brcmf_bus_ops brcmf_ + }; + + ++static void ++brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data, ++ u32 data_len) ++{ ++ __le32 *field; ++ u32 newsize; ++ ++ if (data_len < BRCMF_RAMSIZE_OFFSET + 8) ++ return; ++ ++ field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET]; ++ if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC) ++ return; ++ field++; ++ newsize = le32_to_cpup(field); ++ ++ brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n", ++ newsize); ++ devinfo->ci->ramsize = newsize; ++} ++ ++ + static int + brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, + u32 sharedram_addr) +@@ -1694,6 +1720,13 @@ static void brcmf_pcie_setup(struct devi + + brcmf_pcie_attach(devinfo); + ++ /* Some of the firmwares have the size of the memory of the device ++ * defined inside the firmware. This is because part of the memory in ++ * the device is shared and the devision is determined by FW. Parse ++ * the firmware and adjust the chip memory size now. ++ */ ++ brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size); ++ + ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len); + if (ret) + goto fail; diff --git a/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch b/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch new file mode 100644 index 0000000000..ca03ffe4b0 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0009-brcmfmac-use-bar1-window-size-as-provided-by-pci-sub.patch @@ -0,0 +1,58 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:58 +0100 +Subject: [PATCH] brcmfmac: use bar1 window size as provided by pci subsystem + +The PCIE bar1 window size is specified by chip. Currently the +ioremap of bar1 was using a define which always matched the size +of bar1, but newer chips can have a different bar1 sizes. With +this patch the ioremap will be called with the by chip provided +window size. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -72,7 +72,6 @@ static struct brcmf_firmware_mapping brc + + #define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ + +-#define BRCMF_PCIE_TCM_MAP_SIZE (4096 * 1024) + #define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024) + + /* backplane addres space accessed by BAR0 */ +@@ -252,7 +251,6 @@ struct brcmf_pciedev_info { + char nvram_name[BRCMF_FW_NAME_LEN]; + void __iomem *regs; + void __iomem *tcm; +- u32 tcm_size; + u32 ram_base; + u32 ram_size; + struct brcmf_chip *ci; +@@ -1592,8 +1590,7 @@ static int brcmf_pcie_get_resource(struc + } + + devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE); +- devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE); +- devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE; ++ devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size); + + if (!devinfo->regs || !devinfo->tcm) { + brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs, +@@ -1602,8 +1599,9 @@ static int brcmf_pcie_get_resource(struc + } + brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n", + devinfo->regs, (unsigned long long)bar0_addr); +- brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n", +- devinfo->tcm, (unsigned long long)bar1_addr); ++ brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n", ++ devinfo->tcm, (unsigned long long)bar1_addr, ++ (unsigned int)bar1_size); + + return 0; + } diff --git a/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch b/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch new file mode 100644 index 0000000000..e4a8f305cf --- /dev/null +++ b/package/kernel/mac80211/patches/344-0010-brcmfmac-add-support-for-the-PCIE-4366c0-chip.patch @@ -0,0 +1,34 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:26:59 +0100 +Subject: [PATCH] brcmfmac: add support for the PCIE 4366c0 chip + +A newer version of the 4366 PCIE chip has been released. Add +support for this version of the chip. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -53,6 +53,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-p + BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); + BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); + BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); ++BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); + BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); + + static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { +@@ -66,7 +67,8 @@ static struct brcmf_firmware_mapping brc + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B), +- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B), ++ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), ++ BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + }; + diff --git a/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch b/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch new file mode 100644 index 0000000000..f99f6dbf07 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0011-brcmfmac-remove-pcie-gen1-support.patch @@ -0,0 +1,221 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:00 +0100 +Subject: [PATCH] brcmfmac: remove pcie gen1 support + +The PCIE bus driver supports older gen1 (v1) chips, but there is no +actual device which is using this older pcie core which is supported +by brcmfmac. Remove all gen1 related code. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -100,9 +100,6 @@ static struct brcmf_firmware_mapping brc + #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 + #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140 + +-#define BRCMF_PCIE_GENREV1 1 +-#define BRCMF_PCIE_GENREV2 2 +- + #define BRCMF_PCIE2_INTA 0x01 + #define BRCMF_PCIE2_INTB 0x02 + +@@ -257,9 +254,7 @@ struct brcmf_pciedev_info { + u32 ram_size; + struct brcmf_chip *ci; + u32 coreid; +- u32 generic_corerev; + struct brcmf_pcie_shared_info shared; +- void (*ringbell)(struct brcmf_pciedev_info *devinfo); + wait_queue_head_t mbdata_resp_wait; + bool mbdata_completed; + bool irq_allocated; +@@ -746,68 +741,22 @@ static void brcmf_pcie_bus_console_read( + } + + +-static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo) +-{ +- u32 reg_value; +- +- brcmf_dbg(PCIE, "RING !\n"); +- reg_value = brcmf_pcie_read_reg32(devinfo, +- BRCMF_PCIE_PCIE2REG_MAILBOXINT); +- reg_value |= BRCMF_PCIE2_INTB; +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, +- reg_value); +-} +- +- +-static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo) +-{ +- brcmf_dbg(PCIE, "RING !\n"); +- /* Any arbitrary value will do, lets use 1 */ +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); +-} +- +- + static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo) + { +- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) +- pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, +- 0); +- else +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, +- 0); ++ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0); + } + + + static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo) + { +- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) +- pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, +- BRCMF_PCIE_INT_DEF); +- else +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, +- BRCMF_PCIE_MB_INT_D2H_DB | +- BRCMF_PCIE_MB_INT_FN0_0 | +- BRCMF_PCIE_MB_INT_FN0_1); ++ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, ++ BRCMF_PCIE_MB_INT_D2H_DB | ++ BRCMF_PCIE_MB_INT_FN0_0 | ++ BRCMF_PCIE_MB_INT_FN0_1); + } + + +-static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg) +-{ +- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; +- u32 status; +- +- status = 0; +- pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status); +- if (status) { +- brcmf_pcie_intr_disable(devinfo); +- brcmf_dbg(PCIE, "Enter\n"); +- return IRQ_WAKE_THREAD; +- } +- return IRQ_NONE; +-} +- +- +-static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg) ++static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) + { + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + +@@ -820,29 +769,7 @@ static irqreturn_t brcmf_pcie_quick_chec + } + + +-static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg) +-{ +- struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; +- const struct pci_dev *pdev = devinfo->pdev; +- u32 status; +- +- devinfo->in_irq = true; +- status = 0; +- pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); +- brcmf_dbg(PCIE, "Enter %x\n", status); +- if (status) { +- pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); +- if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) +- brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev); +- } +- if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) +- brcmf_pcie_intr_enable(devinfo); +- devinfo->in_irq = false; +- return IRQ_HANDLED; +-} +- +- +-static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg) ++static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg) + { + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + u32 status; +@@ -879,28 +806,14 @@ static int brcmf_pcie_request_irq(struct + brcmf_pcie_intr_disable(devinfo); + + brcmf_dbg(PCIE, "Enter\n"); +- /* is it a v1 or v2 implementation */ ++ + pci_enable_msi(pdev); +- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { +- if (request_threaded_irq(pdev->irq, +- brcmf_pcie_quick_check_isr_v1, +- brcmf_pcie_isr_thread_v1, +- IRQF_SHARED, "brcmf_pcie_intr", +- devinfo)) { +- pci_disable_msi(pdev); +- brcmf_err("Failed to request IRQ %d\n", pdev->irq); +- return -EIO; +- } +- } else { +- if (request_threaded_irq(pdev->irq, +- brcmf_pcie_quick_check_isr_v2, +- brcmf_pcie_isr_thread_v2, +- IRQF_SHARED, "brcmf_pcie_intr", +- devinfo)) { +- pci_disable_msi(pdev); +- brcmf_err("Failed to request IRQ %d\n", pdev->irq); +- return -EIO; +- } ++ if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr, ++ brcmf_pcie_isr_thread, IRQF_SHARED, ++ "brcmf_pcie_intr", devinfo)) { ++ pci_disable_msi(pdev); ++ brcmf_err("Failed to request IRQ %d\n", pdev->irq); ++ return -EIO; + } + devinfo->irq_allocated = true; + return 0; +@@ -931,16 +844,9 @@ static void brcmf_pcie_release_irq(struc + if (devinfo->in_irq) + brcmf_err("Still in IRQ (processing) !!!\n"); + +- if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { +- status = 0; +- pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); +- pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); +- } else { +- status = brcmf_pcie_read_reg32(devinfo, +- BRCMF_PCIE_PCIE2REG_MAILBOXINT); +- brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, +- status); +- } ++ status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); ++ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status); ++ + devinfo->irq_allocated = false; + } + +@@ -989,7 +895,9 @@ static int brcmf_pcie_ring_mb_ring_bell( + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + +- devinfo->ringbell(devinfo); ++ brcmf_dbg(PCIE, "RING !\n"); ++ /* Any arbitrary value will do, lets use 1 */ ++ brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); + + return 0; + } +@@ -1503,9 +1411,6 @@ static int brcmf_pcie_download_fw_nvram( + u32 address; + u32 resetintr; + +- devinfo->ringbell = brcmf_pcie_ringbell_v2; +- devinfo->generic_corerev = BRCMF_PCIE_GENREV2; +- + brcmf_dbg(PCIE, "Halt ARM.\n"); + err = brcmf_pcie_enter_download_state(devinfo); + if (err) diff --git a/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch b/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch new file mode 100644 index 0000000000..4adfc2dc64 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0012-brcmfmac-increase-timeout-for-tx-eapol.patch @@ -0,0 +1,30 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:01 +0100 +Subject: [PATCH] brcmfmac: increase timeout for tx eapol + +When keys get set and updated this has to happen after eapol got +transmitted (without key or old key) before the key can be updated. +To make sure the order of sending eapol and configuring key is done +correctly a timeout for tx of eapol is applied. This timeout is set +to 50 msec, which is not always enough. Especially in AP mode and +key updates the timeout may need to be much longer because client(s) +can be in powersave. Increase the timeout from 50 to 950 msec. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -42,7 +42,7 @@ MODULE_AUTHOR("Broadcom Corporation"); + MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); + MODULE_LICENSE("Dual BSD/GPL"); + +-#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(50) ++#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950) + + /* AMPDU rx reordering definitions */ + #define BRCMF_RXREORDER_FLOWID_OFFSET 0 diff --git a/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch b/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch new file mode 100644 index 0000000000..bd62781188 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0013-brcmfmac-move-module-init-and-exit-to-common.patch @@ -0,0 +1,135 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:02 +0100 +Subject: [PATCH] brcmfmac: move module init and exit to common + +In preparation of module parameters for all devices the module init +and exit routines are moved to the common file. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -28,6 +28,10 @@ + #include "tracepoint.h" + #include "common.h" + ++MODULE_AUTHOR("Broadcom Corporation"); ++MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); ++MODULE_LICENSE("Dual BSD/GPL"); ++ + const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 +@@ -221,7 +225,7 @@ void __brcmf_dbg(u32 level, const char * + } + #endif + +-void brcmf_mp_attach(void) ++static void brcmf_mp_attach(void) + { + strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path, + BRCMF_FW_ALTPATH_LEN); +@@ -249,3 +253,33 @@ void brcmf_mp_device_detach(struct brcmf + kfree(drvr->settings); + } + ++static int __init brcmfmac_module_init(void) ++{ ++ int err; ++ ++ /* Initialize debug system first */ ++ brcmf_debugfs_init(); ++ ++#ifdef CPTCFG_BRCMFMAC_SDIO ++ brcmf_sdio_init(); ++#endif ++ /* Initialize global module paramaters */ ++ brcmf_mp_attach(); ++ ++ /* Continue the initialization by registering the different busses */ ++ err = brcmf_core_init(); ++ if (err) ++ brcmf_debugfs_exit(); ++ ++ return err; ++} ++ ++static void __exit brcmfmac_module_exit(void) ++{ ++ brcmf_core_exit(); ++ brcmf_debugfs_exit(); ++} ++ ++module_init(brcmfmac_module_init); ++module_exit(brcmfmac_module_exit); ++ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -89,7 +89,6 @@ struct brcmf_mp_device { + struct cc_translate *country_codes; + }; + +-void brcmf_mp_attach(void); + int brcmf_mp_device_attach(struct brcmf_pub *drvr); + void brcmf_mp_device_detach(struct brcmf_pub *drvr); + #ifdef DEBUG +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -38,10 +38,6 @@ + #include "pcie.h" + #include "common.h" + +-MODULE_AUTHOR("Broadcom Corporation"); +-MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +-MODULE_LICENSE("Dual BSD/GPL"); +- + #define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950) + + /* AMPDU rx reordering definitions */ +@@ -1422,19 +1418,15 @@ static void brcmf_driver_register(struct + } + static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register); + +-static int __init brcmfmac_module_init(void) ++int __init brcmf_core_init(void) + { +- brcmf_debugfs_init(); +-#ifdef CPTCFG_BRCMFMAC_SDIO +- brcmf_sdio_init(); +-#endif + if (!schedule_work(&brcmf_driver_work)) + return -EBUSY; + + return 0; + } + +-static void __exit brcmfmac_module_exit(void) ++void __exit brcmf_core_exit(void) + { + cancel_work_sync(&brcmf_driver_work); + +@@ -1447,8 +1439,5 @@ static void __exit brcmfmac_module_exit( + #ifdef CPTCFG_BRCMFMAC_PCIE + brcmf_pcie_exit(); + #endif +- brcmf_debugfs_exit(); + } + +-module_init(brcmfmac_module_init); +-module_exit(brcmfmac_module_exit); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -227,5 +227,7 @@ void brcmf_txflowblock_if(struct brcmf_i + 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); + void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); ++int __init brcmf_core_init(void); ++void __exit brcmf_core_exit(void); + + #endif /* BRCMFMAC_CORE_H */ diff --git a/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch b/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch new file mode 100644 index 0000000000..577ca8ed28 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0014-brcmfmac-add-wowl-gtk-rekeying-offload-support.patch @@ -0,0 +1,260 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:03 +0100 +Subject: [PATCH] brcmfmac: add wowl gtk rekeying offload support + +This patch adds support for gtk rekeying offload and for gtk +rekeying failure during wowl mode. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -3526,6 +3526,10 @@ static void brcmf_report_wowl_wakeind(st + else + wakeup_data.net_detect = cfg->wowl.nd_info; + } ++ if (wakeind & BRCMF_WOWL_GTK_FAILURE) { ++ brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n"); ++ wakeup_data.gtk_rekey_failure = true; ++ } + } else { + wakeup = NULL; + } +@@ -3607,6 +3611,8 @@ static void brcmf_configure_wowl(struct + brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, + brcmf_wowl_nd_results); + } ++ if (wowl->gtk_rekey_failure) ++ wowl_config |= BRCMF_WOWL_GTK_FAILURE; + if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) + wowl_config |= BRCMF_WOWL_UNASSOC; + +@@ -4874,7 +4880,32 @@ static int brcmf_cfg80211_tdls_oper(stru + return ret; + } + +-static struct cfg80211_ops wl_cfg80211_ops = { ++#ifdef CONFIG_PM ++static int ++brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_gtk_rekey_data *gtk) ++{ ++ struct brcmf_if *ifp = netdev_priv(ndev); ++ struct brcmf_gtk_keyinfo_le gtk_le; ++ int ret; ++ ++ brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx); ++ ++ memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck)); ++ memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek)); ++ memcpy(gtk_le.replay_counter, gtk->replay_ctr, ++ sizeof(gtk_le.replay_counter)); ++ ++ ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", >k_le, ++ sizeof(gtk_le)); ++ if (ret < 0) ++ brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret); ++ ++ return ret; ++} ++#endif ++ ++static struct cfg80211_ops brcmf_cfg80211_ops = { + .add_virtual_intf = brcmf_cfg80211_add_iface, + .del_virtual_intf = brcmf_cfg80211_del_iface, + .change_virtual_intf = brcmf_cfg80211_change_iface, +@@ -6139,19 +6170,18 @@ static void brcmf_wiphy_wowl_params(stru + { + #ifdef CONFIG_PM + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +- s32 err; +- u32 wowl_cap; + + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { +- err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); +- if (!err) { +- if (wowl_cap & BRCMF_WOWL_PFN_FOUND) { +- brcmf_wowlan_support.flags |= +- WIPHY_WOWLAN_NET_DETECT; +- init_waitqueue_head(&cfg->wowl.nd_data_wait); +- } ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) { ++ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; ++ init_waitqueue_head(&cfg->wowl.nd_data_wait); + } + } ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) { ++ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY; ++ brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE; ++ } ++ + wiphy->wowlan = &brcmf_wowlan_support; + #endif + } +@@ -6538,6 +6568,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; + struct brcmf_cfg80211_info *cfg; + struct wiphy *wiphy; ++ struct cfg80211_ops *ops; + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + s32 err = 0; +@@ -6549,8 +6580,17 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + return NULL; + } + ++ ops = kzalloc(sizeof(*ops), GFP_KERNEL); ++ if (!ops) ++ return NULL; ++ ++ memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops)); + ifp = netdev_priv(ndev); +- wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); ++#ifdef CONFIG_PM ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) ++ ops->set_rekey_data = brcmf_cfg80211_set_rekey_data; ++#endif ++ wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info)); + if (!wiphy) { + brcmf_err("Could not allocate wiphy device\n"); + return NULL; +@@ -6560,6 +6600,7 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + + cfg = wiphy_priv(wiphy); + cfg->wiphy = wiphy; ++ cfg->ops = ops; + cfg->pub = drvr; + init_vif_event(&cfg->vif_event); + INIT_LIST_HEAD(&cfg->vif_list); +@@ -6686,6 +6727,7 @@ priv_out: + ifp->vif = NULL; + wiphy_out: + brcmf_free_wiphy(wiphy); ++ kfree(ops); + return NULL; + } + +@@ -6696,6 +6738,7 @@ void brcmf_cfg80211_detach(struct brcmf_ + + brcmf_btcoex_detach(cfg); + wiphy_unregister(cfg->wiphy); ++ kfree(cfg->ops); + wl_deinit_priv(cfg); + brcmf_free_wiphy(cfg->wiphy); + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -256,6 +256,7 @@ struct brcmf_cfg80211_wowl { + * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface + * + * @wiphy: wiphy object for cfg80211 interface. ++ * @ops: pointer to copy of ops as registered with wiphy object. + * @conf: dongle configuration. + * @p2p: peer-to-peer specific information. + * @btcoex: Bluetooth coexistence information. +@@ -288,6 +289,7 @@ struct brcmf_cfg80211_wowl { + */ + struct brcmf_cfg80211_info { + struct wiphy *wiphy; ++ struct cfg80211_ops *ops; + struct brcmf_cfg80211_conf *conf; + struct brcmf_p2p_info p2p; + struct brcmf_btcoex_info *btcoex; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -136,6 +136,7 @@ void brcmf_feat_attach(struct brcmf_pub + { + struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); + struct brcmf_pno_macaddr_le pfn_mac; ++ u32 wowl_cap; + s32 err; + + brcmf_feat_firmware_capabilities(ifp); +@@ -143,6 +144,17 @@ void brcmf_feat_attach(struct brcmf_pub + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); + if (drvr->bus_if->wowl_supported) + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) { ++ err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); ++ if (!err) { ++ if (wowl_cap & BRCMF_WOWL_PFN_FOUND) ++ ifp->drvr->feat_flags |= ++ BIT(BRCMF_FEAT_WOWL_ND); ++ if (wowl_cap & BRCMF_WOWL_GTK_FAILURE) ++ ifp->drvr->feat_flags |= ++ BIT(BRCMF_FEAT_WOWL_GTK); ++ } ++ } + /* MBSS does not work for 43362 */ + if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID) + ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -27,6 +27,8 @@ + * RSDB: Real Simultaneous Dual Band + * TDLS: Tunneled Direct Link Setup + * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan. ++ * WOWL_ND: WOWL net detect (PNO) ++ * WOWL_GTK: (WOWL) GTK rekeying offload + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ +@@ -36,7 +38,9 @@ + BRCMF_FEAT_DEF(P2P) \ + BRCMF_FEAT_DEF(RSDB) \ + BRCMF_FEAT_DEF(TDLS) \ +- BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) ++ BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ ++ BRCMF_FEAT_DEF(WOWL_ND) \ ++ BRCMF_FEAT_DEF(WOWL_GTK) + + /* + * Quirks: +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -111,7 +111,9 @@ + /* Wakeup if received matched secured pattern: */ + #define BRCMF_WOWL_SECURE (1 << 25) + /* Wakeup on finding preferred network */ +-#define BRCMF_WOWL_PFN_FOUND (1 << 26) ++#define BRCMF_WOWL_PFN_FOUND (1 << 27) ++/* Wakeup on receiving pairwise key EAP packets: */ ++#define WIPHY_WOWL_EAP_PK (1 << 28) + /* Link Down indication in WoWL mode: */ + #define BRCMF_WOWL_LINKDOWN (1 << 31) + +@@ -136,6 +138,10 @@ + + #define BRCMF_MCSSET_LEN 16 + ++#define BRCMF_RSN_KCK_LENGTH 16 ++#define BRCMF_RSN_KEK_LENGTH 16 ++#define BRCMF_RSN_REPLAY_LEN 8 ++ + /* join preference types for join_pref iovar */ + enum brcmf_join_pref_types { + BRCMF_JOIN_PREF_RSSI = 1, +@@ -789,4 +795,17 @@ struct brcmf_pktcnt_le { + __le32 rx_ocast_good_pkt; + }; + ++/** ++ * struct brcmf_gtk_keyinfo_le - GTP rekey data ++ * ++ * @kck: key confirmation key. ++ * @kek: key encryption key. ++ * @replay_counter: replay counter. ++ */ ++struct brcmf_gtk_keyinfo_le { ++ u8 kck[BRCMF_RSN_KCK_LENGTH]; ++ u8 kek[BRCMF_RSN_KEK_LENGTH]; ++ u8 replay_counter[BRCMF_RSN_REPLAY_LEN]; ++}; ++ + #endif /* FWIL_TYPES_H_ */ diff --git a/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch b/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch new file mode 100644 index 0000000000..2685238925 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0015-brcmfmac-move-platform-data-retrieval-code-to-common.patch @@ -0,0 +1,385 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:04 +0100 +Subject: [PATCH] brcmfmac: move platform data retrieval code to common + +In preparation of module parameters for all devices the module +platform data retrieval is moved from sdio to common. It is still +only used for sdio devices. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -27,8 +27,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -46,7 +44,6 @@ + #include "bus.h" + #include "debug.h" + #include "sdio.h" +-#include "of.h" + #include "core.h" + #include "common.h" + +@@ -106,18 +103,18 @@ static void brcmf_sdiod_dummy_irqhandler + + int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) + { ++ struct brcmfmac_sdio_platform_data *pdata; + int ret = 0; + u8 data; + u32 addr, gpiocontrol; + unsigned long flags; + +- if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) { ++ pdata = sdiodev->pdata; ++ if ((pdata) && (pdata->oob_irq_supported)) { + brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", +- sdiodev->pdata->oob_irq_nr); +- ret = request_irq(sdiodev->pdata->oob_irq_nr, +- brcmf_sdiod_oob_irqhandler, +- sdiodev->pdata->oob_irq_flags, +- "brcmf_oob_intr", ++ pdata->oob_irq_nr); ++ ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, ++ pdata->oob_irq_flags, "brcmf_oob_intr", + &sdiodev->func[1]->dev); + if (ret != 0) { + brcmf_err("request_irq failed %d\n", ret); +@@ -129,7 +126,7 @@ int brcmf_sdiod_intr_register(struct brc + sdiodev->irq_en = true; + spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); + +- ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr); ++ ret = enable_irq_wake(pdata->oob_irq_nr); + if (ret != 0) { + brcmf_err("enable_irq_wake failed %d\n", ret); + return ret; +@@ -158,7 +155,7 @@ int brcmf_sdiod_intr_register(struct brc + + /* redirect, configure and enable io for interrupt signal */ + data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; +- if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH) ++ if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH) + data |= SDIO_SEPINT_ACT_HI; + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); + +@@ -176,9 +173,12 @@ int brcmf_sdiod_intr_register(struct brc + + int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) + { ++ struct brcmfmac_sdio_platform_data *pdata; ++ + brcmf_dbg(SDIO, "Entering\n"); + +- if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) { ++ pdata = sdiodev->pdata; ++ if ((pdata) && (pdata->oob_irq_supported)) { + sdio_claim_host(sdiodev->func[1]); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); +@@ -187,11 +187,10 @@ int brcmf_sdiod_intr_unregister(struct b + if (sdiodev->oob_irq_requested) { + sdiodev->oob_irq_requested = false; + if (sdiodev->irq_wake) { +- disable_irq_wake(sdiodev->pdata->oob_irq_nr); ++ disable_irq_wake(pdata->oob_irq_nr); + sdiodev->irq_wake = false; + } +- free_irq(sdiodev->pdata->oob_irq_nr, +- &sdiodev->func[1]->dev); ++ free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); + sdiodev->irq_en = false; + } + } else { +@@ -1103,8 +1102,6 @@ static const struct sdio_device_id brcmf + }; + MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); + +-static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata; +- + + static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev, + int val) +@@ -1167,10 +1164,7 @@ static int brcmf_ops_sdio_probe(struct s + dev_set_drvdata(&func->dev, bus_if); + dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); + sdiodev->dev = &sdiodev->func[1]->dev; +- sdiodev->pdata = brcmfmac_sdio_pdata; +- +- if (!sdiodev->pdata) +- brcmf_of_probe(sdiodev); ++ sdiodev->pdata = brcmf_get_module_param(sdiodev->dev); + + #ifdef CONFIG_PM_SLEEP + /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ +@@ -1296,7 +1290,7 @@ static const struct dev_pm_ops brcmf_sdi + static struct sdio_driver brcmf_sdmmc_driver = { + .probe = brcmf_ops_sdio_probe, + .remove = brcmf_ops_sdio_remove, +- .name = BRCMFMAC_SDIO_PDATA_NAME, ++ .name = KBUILD_MODNAME, + .id_table = brcmf_sdmmc_ids, + .drv = { + .owner = THIS_MODULE, +@@ -1306,37 +1300,6 @@ static struct sdio_driver brcmf_sdmmc_dr + }, + }; + +-static int __init brcmf_sdio_pd_probe(struct platform_device *pdev) +-{ +- brcmf_dbg(SDIO, "Enter\n"); +- +- brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev); +- +- if (brcmfmac_sdio_pdata->power_on) +- brcmfmac_sdio_pdata->power_on(); +- +- return 0; +-} +- +-static int brcmf_sdio_pd_remove(struct platform_device *pdev) +-{ +- brcmf_dbg(SDIO, "Enter\n"); +- +- if (brcmfmac_sdio_pdata->power_off) +- brcmfmac_sdio_pdata->power_off(); +- +- sdio_unregister_driver(&brcmf_sdmmc_driver); +- +- return 0; +-} +- +-static struct platform_driver brcmf_sdio_pd = { +- .remove = brcmf_sdio_pd_remove, +- .driver = { +- .name = BRCMFMAC_SDIO_PDATA_NAME, +- } +-}; +- + void brcmf_sdio_register(void) + { + int ret; +@@ -1350,19 +1313,6 @@ void brcmf_sdio_exit(void) + { + brcmf_dbg(SDIO, "Enter\n"); + +- if (brcmfmac_sdio_pdata) +- platform_driver_unregister(&brcmf_sdio_pd); +- else +- sdio_unregister_driver(&brcmf_sdmmc_driver); ++ sdio_unregister_driver(&brcmf_sdmmc_driver); + } + +-void __init brcmf_sdio_init(void) +-{ +- int ret; +- +- brcmf_dbg(SDIO, "Enter\n"); +- +- ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); +- if (ret == -ENODEV) +- brcmf_dbg(SDIO, "No platform data available.\n"); +-} +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -27,6 +27,7 @@ + #include "fwil_types.h" + #include "tracepoint.h" + #include "common.h" ++#include "of.h" + + MODULE_AUTHOR("Broadcom Corporation"); + MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +@@ -79,6 +80,7 @@ module_param_named(ignore_probe_fail, br + MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging"); + #endif + ++static struct brcmfmac_sdio_platform_data *brcmfmac_pdata; + struct brcmf_mp_global_t brcmf_mp_global; + + int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) +@@ -231,6 +233,13 @@ static void brcmf_mp_attach(void) + BRCMF_FW_ALTPATH_LEN); + } + ++struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev) ++{ ++ if (!brcmfmac_pdata) ++ brcmf_of_probe(dev, &brcmfmac_pdata); ++ return brcmfmac_pdata; ++} ++ + int brcmf_mp_device_attach(struct brcmf_pub *drvr) + { + drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); +@@ -253,6 +262,35 @@ void brcmf_mp_device_detach(struct brcmf + kfree(drvr->settings); + } + ++static int __init brcmf_common_pd_probe(struct platform_device *pdev) ++{ ++ brcmf_dbg(INFO, "Enter\n"); ++ ++ brcmfmac_pdata = dev_get_platdata(&pdev->dev); ++ ++ if (brcmfmac_pdata->power_on) ++ brcmfmac_pdata->power_on(); ++ ++ return 0; ++} ++ ++static int brcmf_common_pd_remove(struct platform_device *pdev) ++{ ++ brcmf_dbg(INFO, "Enter\n"); ++ ++ if (brcmfmac_pdata->power_off) ++ brcmfmac_pdata->power_off(); ++ ++ return 0; ++} ++ ++static struct platform_driver brcmf_pd = { ++ .remove = brcmf_common_pd_remove, ++ .driver = { ++ .name = BRCMFMAC_SDIO_PDATA_NAME, ++ } ++}; ++ + static int __init brcmfmac_module_init(void) + { + int err; +@@ -260,16 +298,21 @@ static int __init brcmfmac_module_init(v + /* Initialize debug system first */ + brcmf_debugfs_init(); + +-#ifdef CPTCFG_BRCMFMAC_SDIO +- brcmf_sdio_init(); +-#endif ++ /* Get the platform data (if available) for our devices */ ++ err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe); ++ if (err == -ENODEV) ++ brcmf_dbg(INFO, "No platform data available.\n"); ++ + /* Initialize global module paramaters */ + brcmf_mp_attach(); + + /* Continue the initialization by registering the different busses */ + err = brcmf_core_init(); +- if (err) ++ if (err) { + brcmf_debugfs_exit(); ++ if (brcmfmac_pdata) ++ platform_driver_unregister(&brcmf_pd); ++ } + + return err; + } +@@ -277,6 +320,8 @@ static int __init brcmfmac_module_init(v + static void __exit brcmfmac_module_exit(void) + { + brcmf_core_exit(); ++ if (brcmfmac_pdata) ++ platform_driver_unregister(&brcmf_pd); + brcmf_debugfs_exit(); + } + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -15,6 +15,8 @@ + #ifndef BRCMFMAC_COMMON_H + #define BRCMFMAC_COMMON_H + ++#include ++#include + #include "fwil_types.h" + + extern const u8 ALLFFMAC[ETH_ALEN]; +@@ -89,6 +91,7 @@ struct brcmf_mp_device { + struct cc_translate *country_codes; + }; + ++struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev); + int brcmf_mp_device_attach(struct brcmf_pub *drvr); + void brcmf_mp_device_detach(struct brcmf_pub *drvr); + #ifdef DEBUG +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -16,17 +16,16 @@ + #include + #include + #include +-#include +-#include +-#include + + #include + #include "debug.h" +-#include "sdio.h" ++#include "core.h" ++#include "common.h" ++#include "of.h" + +-void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) ++void ++brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio) + { +- struct device *dev = sdiodev->dev; + struct device_node *np = dev->of_node; + int irq; + u32 irqf; +@@ -35,12 +34,12 @@ void brcmf_of_probe(struct brcmf_sdio_de + if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + return; + +- sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL); +- if (!sdiodev->pdata) ++ *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL); ++ if (!(*sdio)) + return; + + if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) +- sdiodev->pdata->drive_strength = val; ++ (*sdio)->drive_strength = val; + + /* make sure there are interrupts defined in the node */ + if (!of_find_property(np, "interrupts", NULL)) +@@ -53,7 +52,7 @@ void brcmf_of_probe(struct brcmf_sdio_de + } + irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); + +- sdiodev->pdata->oob_irq_supported = true; +- sdiodev->pdata->oob_irq_nr = irq; +- sdiodev->pdata->oob_irq_flags = irqf; ++ (*sdio)->oob_irq_supported = true; ++ (*sdio)->oob_irq_nr = irq; ++ (*sdio)->oob_irq_flags = irqf; + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +@@ -14,9 +14,11 @@ + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #ifdef CONFIG_OF +-void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev); ++void ++brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio); + #else +-static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) ++static void brcmf_of_probe(struct device *dev, ++ struct brcmfmac_sdio_platform_data **sdio) + { + } + #endif /* CONFIG_OF */ diff --git a/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch b/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch new file mode 100644 index 0000000000..4e789cfc5a --- /dev/null +++ b/package/kernel/mac80211/patches/344-0016-brcmfmac-keep-ARP-and-ND-offload-enabled-during-WOWL.patch @@ -0,0 +1,69 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:05 +0100 +Subject: [PATCH] brcmfmac: keep ARP and ND offload enabled during WOWL + +Currently ARP and ND (IPv6 Neigbor Discovery) offload get disabled +on entering suspend. However when firmwares support the wowl_cap +iovar then these offload routines can be kept enabled as they +will work during WOWL as well. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -3556,7 +3556,8 @@ static s32 brcmf_cfg80211_resume(struct + brcmf_report_wowl_wakeind(wiphy, ifp); + brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0); + brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0); +- brcmf_configure_arp_nd_offload(ifp, true); ++ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND)) ++ brcmf_configure_arp_nd_offload(ifp, true); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, + cfg->wowl.pre_pmmode); + cfg->wowl.active = false; +@@ -3580,7 +3581,8 @@ static void brcmf_configure_wowl(struct + + brcmf_dbg(TRACE, "Suspend, wowl config.\n"); + +- brcmf_configure_arp_nd_offload(ifp, false); ++ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND)) ++ brcmf_configure_arp_nd_offload(ifp, false); + brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); + brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -147,6 +147,7 @@ void brcmf_feat_attach(struct brcmf_pub + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) { + err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); + if (!err) { ++ ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND); + if (wowl_cap & BRCMF_WOWL_PFN_FOUND) + ifp->drvr->feat_flags |= + BIT(BRCMF_FEAT_WOWL_ND); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -29,6 +29,7 @@ + * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan. + * WOWL_ND: WOWL net detect (PNO) + * WOWL_GTK: (WOWL) GTK rekeying offload ++ * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ +@@ -40,7 +41,8 @@ + BRCMF_FEAT_DEF(TDLS) \ + BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ + BRCMF_FEAT_DEF(WOWL_ND) \ +- BRCMF_FEAT_DEF(WOWL_GTK) ++ BRCMF_FEAT_DEF(WOWL_GTK) \ ++ BRCMF_FEAT_DEF(WOWL_ARP_ND) + + /* + * Quirks: diff --git a/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch b/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch new file mode 100644 index 0000000000..37b68552cc --- /dev/null +++ b/package/kernel/mac80211/patches/344-0017-brcmfmac-switch-to-new-platform-data.patch @@ -0,0 +1,734 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:07 +0100 +Subject: [PATCH] brcmfmac: switch to new platform data + +Platform data is only available for sdio. With this patch a new +platform data structure is being used which allows for platform +data for any device and configurable per device. This patch only +switches to the new structure and adds support for SDIO devices. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -103,7 +103,7 @@ static void brcmf_sdiod_dummy_irqhandler + + int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) + { +- struct brcmfmac_sdio_platform_data *pdata; ++ struct brcmfmac_sdio_pd *pdata; + int ret = 0; + u8 data; + u32 addr, gpiocontrol; +@@ -173,7 +173,7 @@ int brcmf_sdiod_intr_register(struct brc + + int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) + { +- struct brcmfmac_sdio_platform_data *pdata; ++ struct brcmfmac_sdio_pd *pdata; + + brcmf_dbg(SDIO, "Entering\n"); + +@@ -1164,17 +1164,6 @@ static int brcmf_ops_sdio_probe(struct s + dev_set_drvdata(&func->dev, bus_if); + dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); + sdiodev->dev = &sdiodev->func[1]->dev; +- sdiodev->pdata = brcmf_get_module_param(sdiodev->dev); +- +-#ifdef CONFIG_PM_SLEEP +- /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ +- * is true or when platform data OOB irq is true). +- */ +- if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && +- ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || +- (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) +- bus_if->wowl_supported = true; +-#endif + + brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -6459,8 +6459,8 @@ int brcmf_cfg80211_wait_vif_event(struct + static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], + struct brcmf_fil_country_le *ccreq) + { +- struct cc_translate *country_codes; +- struct cc_entry *cc; ++ struct brcmfmac_pd_cc *country_codes; ++ struct brcmfmac_pd_cc_entry *cc; + s32 found_index; + int i; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -80,7 +80,7 @@ module_param_named(ignore_probe_fail, br + MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging"); + #endif + +-static struct brcmfmac_sdio_platform_data *brcmfmac_pdata; ++static struct brcmfmac_platform_data *brcmfmac_pdata; + struct brcmf_mp_global_t brcmf_mp_global; + + int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) +@@ -229,15 +229,46 @@ void __brcmf_dbg(u32 level, const char * + + static void brcmf_mp_attach(void) + { ++ /* If module param firmware path is set then this will always be used, ++ * if not set then if available use the platform data version. To make ++ * sure it gets initialized at all, always copy the module param version ++ */ + strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path, + BRCMF_FW_ALTPATH_LEN); ++ if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) && ++ (brcmf_mp_global.firmware_path[0] == '\0')) { ++ strlcpy(brcmf_mp_global.firmware_path, ++ brcmfmac_pdata->fw_alternative_path, ++ BRCMF_FW_ALTPATH_LEN); ++ } + } + +-struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev) +-{ +- if (!brcmfmac_pdata) +- brcmf_of_probe(dev, &brcmfmac_pdata); +- return brcmfmac_pdata; ++struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, ++ enum brcmf_bus_type bus_type, ++ u32 chip, u32 chiprev) ++{ ++ struct brcmfmac_sdio_pd *pdata; ++ struct brcmfmac_pd_device *device_pd; ++ int i; ++ ++ if (brcmfmac_pdata) { ++ for (i = 0; i < brcmfmac_pdata->device_count; i++) { ++ device_pd = &brcmfmac_pdata->devices[i]; ++ if ((device_pd->bus_type == bus_type) && ++ (device_pd->id == chip) && ++ ((device_pd->rev == chiprev) || ++ (device_pd->rev == -1))) { ++ brcmf_dbg(INFO, "Platform data for device found\n"); ++ if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO) ++ return &device_pd->bus.sdio; ++ break; ++ } ++ } ++ } ++ pdata = NULL; ++ brcmf_of_probe(dev, &pdata); ++ ++ return pdata; + } + + int brcmf_mp_device_attach(struct brcmf_pub *drvr) +@@ -287,7 +318,7 @@ static int brcmf_common_pd_remove(struct + static struct platform_driver brcmf_pd = { + .remove = brcmf_common_pd_remove, + .driver = { +- .name = BRCMFMAC_SDIO_PDATA_NAME, ++ .name = BRCMFMAC_PDATA_NAME, + } + }; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -16,7 +16,7 @@ + #define BRCMFMAC_COMMON_H + + #include +-#include ++#include + #include "fwil_types.h" + + extern const u8 ALLFFMAC[ETH_ALEN]; +@@ -43,33 +43,6 @@ struct brcmf_mp_global_t { + extern struct brcmf_mp_global_t brcmf_mp_global; + + /** +- * struct cc_entry - Struct for translating user space country code (iso3166) to +- * firmware country code and revision. +- * +- * @iso3166: iso3166 alpha 2 country code string. +- * @cc: firmware country code string. +- * @rev: firmware country code revision. +- */ +-struct cc_entry { +- char iso3166[BRCMF_COUNTRY_BUF_SZ]; +- char cc[BRCMF_COUNTRY_BUF_SZ]; +- s32 rev; +-}; +- +-/** +- * struct cc_translate - Struct for translating country codes as set by user +- * space to a country code and rev which can be used by +- * firmware. +- * +- * @table_size: number of entries in table (> 0) +- * @table: dynamic array of 1 or more elements with translation information. +- */ +-struct cc_translate { +- int table_size; +- struct cc_entry table[0]; +-}; +- +-/** + * struct brcmf_mp_device - Device module paramaters. + * + * @sdiod_txglomsz: SDIO txglom size. +@@ -88,10 +61,12 @@ struct brcmf_mp_device { + int fcmode; + bool roamoff; + bool ignore_probe_fail; +- struct cc_translate *country_codes; ++ struct brcmfmac_pd_cc *country_codes; + }; + +-struct brcmfmac_sdio_platform_data *brcmf_get_module_param(struct device *dev); ++struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, ++ enum brcmf_bus_type bus_type, ++ u32 chip, u32 chiprev); + int brcmf_mp_device_attach(struct brcmf_pub *drvr); + void brcmf_mp_device_detach(struct brcmf_pub *drvr); + #ifdef DEBUG +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -23,8 +23,7 @@ + #include "common.h" + #include "of.h" + +-void +-brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio) ++void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) + { + struct device_node *np = dev->of_node; + int irq; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +@@ -15,10 +15,9 @@ + */ + #ifdef CONFIG_OF + void +-brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_platform_data **sdio); ++brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio); + #else +-static void brcmf_of_probe(struct device *dev, +- struct brcmfmac_sdio_platform_data **sdio) ++static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) + { + } + #endif /* CONFIG_OF */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -33,8 +33,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -44,6 +42,8 @@ + #include "sdio.h" + #include "chip.h" + #include "firmware.h" ++#include "core.h" ++#include "common.h" + + #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) + #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) +@@ -3775,26 +3775,28 @@ static const struct brcmf_buscore_ops br + static bool + brcmf_sdio_probe_attach(struct brcmf_sdio *bus) + { ++ struct brcmf_sdio_dev *sdiodev; + u8 clkctl = 0; + int err = 0; + int reg_addr; + u32 reg_val; + u32 drivestrength; + +- sdio_claim_host(bus->sdiodev->func[1]); ++ sdiodev = bus->sdiodev; ++ sdio_claim_host(sdiodev->func[1]); + + pr_debug("F1 signature read @0x18000000=0x%4x\n", +- brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); ++ brcmf_sdiod_regrl(sdiodev, SI_ENUM_BASE, NULL)); + + /* + * Force PLL off until brcmf_chip_attach() + * programs PLL control regs + */ + +- brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, ++ brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + BRCMF_INIT_CLKCTL1, &err); + if (!err) +- clkctl = brcmf_sdiod_regrb(bus->sdiodev, ++ clkctl = brcmf_sdiod_regrb(sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + + if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { +@@ -3803,50 +3805,77 @@ brcmf_sdio_probe_attach(struct brcmf_sdi + goto fail; + } + +- bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); ++ bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops); + if (IS_ERR(bus->ci)) { + brcmf_err("brcmf_chip_attach failed!\n"); + bus->ci = NULL; + goto fail; + } ++ sdiodev->pdata = brcmf_get_module_param(sdiodev->dev, ++ BRCMF_BUSTYPE_SDIO, ++ bus->ci->chip, ++ bus->ci->chiprev); ++ /* platform specific configuration: ++ * alignments must be at least 4 bytes for ADMA ++ */ ++ bus->head_align = ALIGNMENT; ++ bus->sgentry_align = ALIGNMENT; ++ if (sdiodev->pdata) { ++ if (sdiodev->pdata->sd_head_align > ALIGNMENT) ++ bus->head_align = sdiodev->pdata->sd_head_align; ++ if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) ++ bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; ++ } ++ /* allocate scatter-gather table. sg support ++ * will be disabled upon allocation failure. ++ */ ++ brcmf_sdiod_sgtable_alloc(sdiodev); ++ ++#ifdef CONFIG_PM_SLEEP ++ /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ ++ * is true or when platform data OOB irq is true). ++ */ ++ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && ++ ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || ++ (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) ++ sdiodev->bus_if->wowl_supported = true; ++#endif + + if (brcmf_sdio_kso_init(bus)) { + brcmf_err("error enabling KSO\n"); + goto fail; + } + +- if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength)) +- drivestrength = bus->sdiodev->pdata->drive_strength; ++ if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength)) ++ drivestrength = sdiodev->pdata->drive_strength; + else + drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; +- brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); ++ brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength); + + /* Set card control so an SDIO card reset does a WLAN backplane reset */ +- reg_val = brcmf_sdiod_regrb(bus->sdiodev, +- SDIO_CCCR_BRCM_CARDCTRL, &err); ++ reg_val = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err); + if (err) + goto fail; + + reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET; + +- brcmf_sdiod_regwb(bus->sdiodev, +- SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err); ++ brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err); + if (err) + goto fail; + + /* set PMUControl so a backplane reset does PMU state reload */ + reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); +- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); ++ reg_val = brcmf_sdiod_regrl(sdiodev, reg_addr, &err); + if (err) + goto fail; + + reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); + +- brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err); ++ brcmf_sdiod_regwl(sdiodev, reg_addr, reg_val, &err); + if (err) + goto fail; + +- sdio_release_host(bus->sdiodev->func[1]); ++ sdio_release_host(sdiodev->func[1]); + + brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); + +@@ -3867,7 +3896,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi + return true; + + fail: +- sdio_release_host(bus->sdiodev->func[1]); ++ sdio_release_host(sdiodev->func[1]); + return false; + } + +@@ -4045,18 +4074,6 @@ struct brcmf_sdio *brcmf_sdio_probe(stru + bus->txminmax = BRCMF_TXMINMAX; + bus->tx_seq = SDPCM_SEQ_WRAP - 1; + +- /* platform specific configuration: +- * alignments must be at least 4 bytes for ADMA +- */ +- bus->head_align = ALIGNMENT; +- bus->sgentry_align = ALIGNMENT; +- if (sdiodev->pdata) { +- if (sdiodev->pdata->sd_head_align > ALIGNMENT) +- bus->head_align = sdiodev->pdata->sd_head_align; +- if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) +- bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; +- } +- + /* single-threaded workqueue */ + wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM, + dev_name(&sdiodev->func[1]->dev)); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -184,7 +184,7 @@ struct brcmf_sdio_dev { + struct brcmf_sdio *bus; + struct device *dev; + struct brcmf_bus *bus_if; +- struct brcmfmac_sdio_platform_data *pdata; ++ struct brcmfmac_sdio_pd *pdata; + bool oob_irq_requested; + bool irq_en; /* irq enable flags */ + spinlock_t irq_en_lock; +--- a/include/linux/platform_data/brcmfmac-sdio.h ++++ /dev/null +@@ -1,135 +0,0 @@ +-/* +- * Copyright (c) 2013 Broadcom Corporation +- * +- * Permission to use, copy, modify, and/or distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- */ +- +-#ifndef _LINUX_BRCMFMAC_PLATFORM_H +-#define _LINUX_BRCMFMAC_PLATFORM_H +- +-/* +- * Platform specific driver functions and data. Through the platform specific +- * device data functions can be provided to help the brcmfmac driver to +- * operate with the device in combination with the used platform. +- * +- * Use the platform data in the following (similar) way: +- * +- * +-#include +- +- +-static void brcmfmac_power_on(void) +-{ +-} +- +-static void brcmfmac_power_off(void) +-{ +-} +- +-static void brcmfmac_reset(void) +-{ +-} +- +-static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = { +- .power_on = brcmfmac_power_on, +- .power_off = brcmfmac_power_off, +- .reset = brcmfmac_reset +-}; +- +-static struct platform_device brcmfmac_device = { +- .name = BRCMFMAC_SDIO_PDATA_NAME, +- .id = PLATFORM_DEVID_NONE, +- .dev.platform_data = &brcmfmac_sdio_pdata +-}; +- +-void __init brcmfmac_init_pdata(void) +-{ +- brcmfmac_sdio_pdata.oob_irq_supported = true; +- brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB); +- brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ | +- IORESOURCE_IRQ_HIGHLEVEL; +- platform_device_register(&brcmfmac_device); +-} +- * +- * +- * Note: the brcmfmac can be loaded as module or be statically built-in into +- * the kernel. If built-in then do note that it uses module_init (and +- * module_exit) routines which equal device_initcall. So if you intend to +- * create a module with the platform specific data for the brcmfmac and have +- * it built-in to the kernel then use a higher initcall then device_initcall +- * (see init.h). If this is not done then brcmfmac will load without problems +- * but will not pickup the platform data. +- * +- * When the driver does not "detect" platform driver data then it will continue +- * without reporting anything and just assume there is no data needed. Which is +- * probably true for most platforms. +- * +- * Explanation of the platform_data fields: +- * +- * drive_strength: is the preferred drive_strength to be used for the SDIO +- * pins. If 0 then a default value will be used. This is the target drive +- * strength, the exact drive strength which will be used depends on the +- * capabilities of the device. +- * +- * oob_irq_supported: does the board have support for OOB interrupts. SDIO +- * in-band interrupts are relatively slow and for having less overhead on +- * interrupt processing an out of band interrupt can be used. If the HW +- * supports this then enable this by setting this field to true and configure +- * the oob related fields. +- * +- * oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are +- * used for registering the irq using request_irq function. +- * +- * broken_sg_support: flag for broken sg list support of SDIO host controller. +- * Set this to true if the SDIO host controller has higher align requirement +- * than 32 bytes for each scatterlist item. +- * +- * sd_head_align: alignment requirement for start of data buffer +- * +- * sd_sgentry_align: length alignment requirement for each sg entry +- * +- * power_on: This function is called by the brcmfmac when the module gets +- * loaded. This can be particularly useful for low power devices. The platform +- * spcific routine may for example decide to power up the complete device. +- * If there is no use-case for this function then provide NULL. +- * +- * power_off: This function is called by the brcmfmac when the module gets +- * unloaded. At this point the device can be powered down or otherwise be reset. +- * So if an actual power_off is not supported but reset is then reset the device +- * when this function gets called. This can be particularly useful for low power +- * devices. If there is no use-case for this function (either power-down or +- * reset) then provide NULL. +- * +- * reset: This function can get called if the device communication broke down. +- * This functionality is particularly useful in case of SDIO type devices. It is +- * possible to reset a dongle via sdio data interface, but it requires that +- * this is fully functional. This function is chip/module specific and this +- * function should return only after the complete reset has completed. +- */ +- +-#define BRCMFMAC_SDIO_PDATA_NAME "brcmfmac_sdio" +- +-struct brcmfmac_sdio_platform_data { +- unsigned int drive_strength; +- bool oob_irq_supported; +- unsigned int oob_irq_nr; +- unsigned long oob_irq_flags; +- bool broken_sg_support; +- unsigned short sd_head_align; +- unsigned short sd_sgentry_align; +- void (*power_on)(void); +- void (*power_off)(void); +- void (*reset)(void); +-}; +- +-#endif /* _LINUX_BRCMFMAC_PLATFORM_H */ +--- /dev/null ++++ b/include/linux/platform_data/brcmfmac.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (c) 201 Broadcom Corporation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN ++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _LINUX_BRCMFMAC_PLATFORM_H ++#define _LINUX_BRCMFMAC_PLATFORM_H ++ ++ ++#define BRCMFMAC_PDATA_NAME "brcmfmac" ++ ++#define BRCMFMAC_COUNTRY_BUF_SZ 4 ++ ++ ++/* ++ * Platform specific driver functions and data. Through the platform specific ++ * device data functions and data can be provided to help the brcmfmac driver to ++ * operate with the device in combination with the used platform. ++ */ ++ ++ ++/** ++ * Note: the brcmfmac can be loaded as module or be statically built-in into ++ * the kernel. If built-in then do note that it uses module_init (and ++ * module_exit) routines which equal device_initcall. So if you intend to ++ * create a module with the platform specific data for the brcmfmac and have ++ * it built-in to the kernel then use a higher initcall then device_initcall ++ * (see init.h). If this is not done then brcmfmac will load without problems ++ * but will not pickup the platform data. ++ * ++ * When the driver does not "detect" platform driver data then it will continue ++ * without reporting anything and just assume there is no data needed. Which is ++ * probably true for most platforms. ++ */ ++ ++/** ++ * enum brcmf_bus_type - Bus type identifier. Currently SDIO, USB and PCIE are ++ * supported. ++ */ ++enum brcmf_bus_type { ++ BRCMF_BUSTYPE_SDIO, ++ BRCMF_BUSTYPE_USB, ++ BRCMF_BUSTYPE_PCIE ++}; ++ ++ ++/** ++ * struct brcmfmac_sdio_pd - SDIO Device specific platform data. ++ * ++ * @txglomsz: SDIO txglom size. Use 0 if default of driver is to be ++ * used. ++ * @drive_strength: is the preferred drive_strength to be used for the SDIO ++ * pins. If 0 then a default value will be used. This is ++ * the target drive strength, the exact drive strength ++ * which will be used depends on the capabilities of the ++ * device. ++ * @oob_irq_supported: does the board have support for OOB interrupts. SDIO ++ * in-band interrupts are relatively slow and for having ++ * less overhead on interrupt processing an out of band ++ * interrupt can be used. If the HW supports this then ++ * enable this by setting this field to true and configure ++ * the oob related fields. ++ * @oob_irq_nr, ++ * @oob_irq_flags: the OOB interrupt information. The values are used for ++ * registering the irq using request_irq function. ++ * @broken_sg_support: flag for broken sg list support of SDIO host controller. ++ * Set this to true if the SDIO host controller has higher ++ * align requirement than 32 bytes for each scatterlist ++ * item. ++ * @sd_head_align: alignment requirement for start of data buffer. ++ * @sd_sgentry_align: length alignment requirement for each sg entry. ++ * @reset: This function can get called if the device communication ++ * broke down. This functionality is particularly useful in ++ * case of SDIO type devices. It is possible to reset a ++ * dongle via sdio data interface, but it requires that ++ * this is fully functional. This function is chip/module ++ * specific and this function should return only after the ++ * complete reset has completed. ++ */ ++struct brcmfmac_sdio_pd { ++ int txglomsz; ++ unsigned int drive_strength; ++ bool oob_irq_supported; ++ unsigned int oob_irq_nr; ++ unsigned long oob_irq_flags; ++ bool broken_sg_support; ++ unsigned short sd_head_align; ++ unsigned short sd_sgentry_align; ++ void (*reset)(void); ++}; ++ ++/** ++ * struct brcmfmac_pd_cc_entry - Struct for translating user space country code ++ * (iso3166) to firmware country code and ++ * revision. ++ * ++ * @iso3166: iso3166 alpha 2 country code string. ++ * @cc: firmware country code string. ++ * @rev: firmware country code revision. ++ */ ++struct brcmfmac_pd_cc_entry { ++ char iso3166[BRCMFMAC_COUNTRY_BUF_SZ]; ++ char cc[BRCMFMAC_COUNTRY_BUF_SZ]; ++ s32 rev; ++}; ++ ++/** ++ * struct brcmfmac_pd_cc - Struct for translating country codes as set by user ++ * space to a country code and rev which can be used by ++ * firmware. ++ * ++ * @table_size: number of entries in table (> 0) ++ * @table: array of 1 or more elements with translation information. ++ */ ++struct brcmfmac_pd_cc { ++ int table_size; ++ struct brcmfmac_pd_cc_entry table[0]; ++}; ++ ++/** ++ * struct brcmfmac_pd_device - Device specific platform data. (id/rev/bus_type) ++ * is the unique identifier of the device. ++ * ++ * @id: ID of the device for which this data is. In case of SDIO ++ * or PCIE this is the chipid as identified by chip.c In ++ * case of USB this is the chipid as identified by the ++ * device query. ++ * @rev: chip revision, see id. ++ * @bus_type: The type of bus. Some chipid/rev exist for different bus ++ * types. Each bus type has its own set of settings. ++ * @feature_disable: Bitmask of features to disable (override), See feature.c ++ * in brcmfmac for details. ++ * @country_codes: If available, pointer to struct for translating country ++ * codes. ++ * @bus: Bus specific (union) device settings. Currently only ++ * SDIO. ++ */ ++struct brcmfmac_pd_device { ++ unsigned int id; ++ unsigned int rev; ++ enum brcmf_bus_type bus_type; ++ unsigned int feature_disable; ++ struct brcmfmac_pd_cc *country_codes; ++ union { ++ struct brcmfmac_sdio_pd sdio; ++ } bus; ++}; ++ ++/** ++ * struct brcmfmac_platform_data - BRCMFMAC specific platform data. ++ * ++ * @power_on: This function is called by the brcmfmac driver when the module ++ * gets loaded. This can be particularly useful for low power ++ * devices. The platform spcific routine may for example decide to ++ * power up the complete device. If there is no use-case for this ++ * function then provide NULL. ++ * @power_off: This function is called by the brcmfmac when the module gets ++ * unloaded. At this point the devices can be powered down or ++ * otherwise be reset. So if an actual power_off is not supported ++ * but reset is supported by the devices then reset the devices ++ * when this function gets called. This can be particularly useful ++ * for low power devices. If there is no use-case for this ++ * function then provide NULL. ++ */ ++struct brcmfmac_platform_data { ++ void (*power_on)(void); ++ void (*power_off)(void); ++ char *fw_alternative_path; ++ int device_count; ++ struct brcmfmac_pd_device devices[0]; ++}; ++ ++ ++#endif /* _LINUX_BRCMFMAC_PLATFORM_H */ diff --git a/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch b/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch new file mode 100644 index 0000000000..34341d7f18 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0018-brcmfmac-merge-platform-data-and-module-paramaters.patch @@ -0,0 +1,607 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:08 +0100 +Subject: [PATCH] brcmfmac: merge platform data and module paramaters + +Merge module parameters and platform data in one struct. This is the +last step to move to the new platform data per device. Now parameters +of platform data will be merged with module parameters per device. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -109,8 +109,8 @@ int brcmf_sdiod_intr_register(struct brc + u32 addr, gpiocontrol; + unsigned long flags; + +- pdata = sdiodev->pdata; +- if ((pdata) && (pdata->oob_irq_supported)) { ++ pdata = &sdiodev->settings->bus.sdio; ++ if (pdata->oob_irq_supported) { + brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", + pdata->oob_irq_nr); + ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, +@@ -177,8 +177,8 @@ int brcmf_sdiod_intr_unregister(struct b + + brcmf_dbg(SDIO, "Entering\n"); + +- pdata = sdiodev->pdata; +- if ((pdata) && (pdata->oob_irq_supported)) { ++ pdata = &sdiodev->settings->bus.sdio; ++ if (pdata->oob_irq_supported) { + sdio_claim_host(sdiodev->func[1]); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); +@@ -522,7 +522,7 @@ static int brcmf_sdiod_sglist_rw(struct + target_list = pktlist; + /* for host with broken sg support, prepare a page aligned list */ + __skb_queue_head_init(&local_list); +- if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) { ++ if (!write && sdiodev->settings->bus.sdio.broken_sg_support) { + req_sz = 0; + skb_queue_walk(pktlist, pkt_next) + req_sz += pkt_next->len; +@@ -629,7 +629,7 @@ static int brcmf_sdiod_sglist_rw(struct + } + } + +- if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) { ++ if (!write && sdiodev->settings->bus.sdio.broken_sg_support) { + local_pkt_next = local_list.next; + orig_offset = 0; + skb_queue_walk(pktlist, pkt_next) { +@@ -900,7 +900,7 @@ void brcmf_sdiod_sgtable_alloc(struct br + return; + + nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, +- sdiodev->bus_if->drvr->settings->sdiod_txglomsz); ++ sdiodev->settings->bus.sdio.txglomsz); + nents += (nents >> 4) + 1; + + WARN_ON(nents > sdiodev->max_segment_count); +@@ -912,7 +912,7 @@ void brcmf_sdiod_sgtable_alloc(struct br + sdiodev->sg_support = false; + } + +- sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz; ++ sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz; + } + + #ifdef CONFIG_PM_SLEEP +@@ -1246,8 +1246,8 @@ static int brcmf_ops_sdio_suspend(struct + + sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->wowl_enabled) { +- if (sdiodev->pdata->oob_irq_supported) +- enable_irq_wake(sdiodev->pdata->oob_irq_nr); ++ if (sdiodev->settings->bus.sdio.oob_irq_supported) ++ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); + else + sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -43,6 +43,8 @@ enum brcmf_bus_protocol_type { + BRCMF_PROTO_MSGBUF + }; + ++struct brcmf_mp_device; ++ + struct brcmf_bus_dcmd { + char *name; + char *param; +@@ -217,7 +219,7 @@ bool brcmf_c_prec_enq(struct device *dev + void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp); + + /* Indication from bus module regarding presence/insertion of dongle. */ +-int brcmf_attach(struct device *dev); ++int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings); + /* Indication from bus module regarding removal/absence of dongle */ + void brcmf_detach(struct device *dev); + /* Indication from bus module that dongle should be reset */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -243,14 +243,35 @@ static void brcmf_mp_attach(void) + } + } + +-struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, +- enum brcmf_bus_type bus_type, +- u32 chip, u32 chiprev) ++struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, ++ enum brcmf_bus_type bus_type, ++ u32 chip, u32 chiprev) + { +- struct brcmfmac_sdio_pd *pdata; ++ struct brcmf_mp_device *settings; + struct brcmfmac_pd_device *device_pd; ++ bool found; + int i; + ++ brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip, ++ chiprev); ++ settings = kzalloc(sizeof(*settings), GFP_ATOMIC); ++ if (!settings) ++ return NULL; ++ ++ /* start by using the module paramaters */ ++ settings->p2p_enable = !!brcmf_p2p_enable; ++ settings->feature_disable = brcmf_feature_disable; ++ settings->fcmode = brcmf_fcmode; ++ settings->roamoff = !!brcmf_roamoff; ++#ifdef DEBUG ++ settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; ++#endif ++ ++ if (bus_type == BRCMF_BUSTYPE_SDIO) ++ settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz; ++ ++ /* See if there is any device specific platform data configured */ ++ found = false; + if (brcmfmac_pdata) { + for (i = 0; i < brcmfmac_pdata->device_count; i++) { + device_pd = &brcmfmac_pdata->devices[i]; +@@ -259,38 +280,29 @@ struct brcmfmac_sdio_pd *brcmf_get_modul + ((device_pd->rev == chiprev) || + (device_pd->rev == -1))) { + brcmf_dbg(INFO, "Platform data for device found\n"); ++ settings->country_codes = ++ device_pd->country_codes; + if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO) +- return &device_pd->bus.sdio; ++ memcpy(&settings->bus.sdio, ++ &device_pd->bus.sdio, ++ sizeof(settings->bus.sdio)); ++ found = true; + break; + } + } + } +- pdata = NULL; +- brcmf_of_probe(dev, &pdata); +- +- return pdata; +-} +- +-int brcmf_mp_device_attach(struct brcmf_pub *drvr) +-{ +- drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC); +- if (!drvr->settings) +- return -ENOMEM; +- +- drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz; +- drvr->settings->p2p_enable = !!brcmf_p2p_enable; +- drvr->settings->feature_disable = brcmf_feature_disable; +- drvr->settings->fcmode = brcmf_fcmode; +- drvr->settings->roamoff = !!brcmf_roamoff; +-#ifdef DEBUG +- drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; +-#endif +- return 0; ++ if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) { ++ /* No platform data for this device. In case of SDIO try OF ++ * (Open Firwmare) Device Tree. ++ */ ++ brcmf_of_probe(dev, &settings->bus.sdio); ++ } ++ return settings; + } + +-void brcmf_mp_device_detach(struct brcmf_pub *drvr) ++void brcmf_release_module_param(struct brcmf_mp_device *module_param) + { +- kfree(drvr->settings); ++ kfree(module_param); + } + + static int __init brcmf_common_pd_probe(struct platform_device *pdev) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -45,41 +45,30 @@ extern struct brcmf_mp_global_t brcmf_mp + /** + * struct brcmf_mp_device - Device module paramaters. + * +- * @sdiod_txglomsz: SDIO txglom size. +- * @joinboost_5g_rssi: 5g rssi booost for preferred join selection. + * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant). + * @feature_disable: Feature_disable bitmask. + * @fcmode: FWS flow control. + * @roamoff: Firmware roaming off? ++ * @ignore_probe_fail: Ignore probe failure. + * @country_codes: If available, pointer to struct for translating country codes ++ * @bus: Bus specific platform data. Only SDIO at the mmoment. + */ + struct brcmf_mp_device { +- int sdiod_txglomsz; +- int joinboost_5g_rssi; +- bool p2p_enable; +- int feature_disable; +- int fcmode; +- bool roamoff; +- bool ignore_probe_fail; ++ bool p2p_enable; ++ unsigned int feature_disable; ++ int fcmode; ++ bool roamoff; ++ bool ignore_probe_fail; + struct brcmfmac_pd_cc *country_codes; ++ union { ++ struct brcmfmac_sdio_pd sdio; ++ } bus; + }; + +-struct brcmfmac_sdio_pd *brcmf_get_module_param(struct device *dev, +- enum brcmf_bus_type bus_type, +- u32 chip, u32 chiprev); +-int brcmf_mp_device_attach(struct brcmf_pub *drvr); +-void brcmf_mp_device_detach(struct brcmf_pub *drvr); +-#ifdef DEBUG +-static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr) +-{ +- return drvr->settings->ignore_probe_fail; +-} +-#else +-static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr) +-{ +- return false; +-} +-#endif ++struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, ++ enum brcmf_bus_type bus_type, ++ u32 chip, u32 chiprev); ++void brcmf_release_module_param(struct brcmf_mp_device *module_param); + + /* Sets dongle media info (drv_version, mac address). */ + int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1104,7 +1104,7 @@ static int brcmf_inet6addr_changed(struc + } + #endif + +-int brcmf_attach(struct device *dev) ++int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) + { + struct brcmf_pub *drvr = NULL; + int ret = 0; +@@ -1126,10 +1126,7 @@ int brcmf_attach(struct device *dev) + drvr->hdrlen = 0; + drvr->bus_if = dev_get_drvdata(dev); + drvr->bus_if->drvr = drvr; +- +- /* Initialize device specific settings */ +- if (brcmf_mp_device_attach(drvr)) +- goto fail; ++ drvr->settings = settings; + + /* attach debug facilities */ + brcmf_debug_attach(drvr); +@@ -1274,7 +1271,7 @@ fail: + brcmf_net_detach(p2p_ifp->ndev); + drvr->iflist[0] = NULL; + drvr->iflist[1] = NULL; +- if (brcmf_ignoring_probe_fail(drvr)) ++ if (drvr->settings->ignore_probe_fail) + ret = 0; + + return ret; +@@ -1350,8 +1347,6 @@ void brcmf_detach(struct device *dev) + + brcmf_proto_detach(drvr); + +- brcmf_mp_device_detach(drvr); +- + brcmf_debug_detach(drvr); + bus_if->drvr = NULL; + kfree(drvr); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -23,7 +23,7 @@ + #include "common.h" + #include "of.h" + +-void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) ++void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio) + { + struct device_node *np = dev->of_node; + int irq; +@@ -33,12 +33,8 @@ void brcmf_of_probe(struct device *dev, + if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + return; + +- *sdio = devm_kzalloc(dev, sizeof(*sdio), GFP_KERNEL); +- if (!(*sdio)) +- return; +- + if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) +- (*sdio)->drive_strength = val; ++ sdio->drive_strength = val; + + /* make sure there are interrupts defined in the node */ + if (!of_find_property(np, "interrupts", NULL)) +@@ -51,7 +47,7 @@ void brcmf_of_probe(struct device *dev, + } + irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); + +- (*sdio)->oob_irq_supported = true; +- (*sdio)->oob_irq_nr = irq; +- (*sdio)->oob_irq_flags = irqf; ++ sdio->oob_irq_supported = true; ++ sdio->oob_irq_nr = irq; ++ sdio->oob_irq_flags = irqf; + } +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +@@ -14,10 +14,9 @@ + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #ifdef CONFIG_OF +-void +-brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio); ++void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio); + #else +-static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd **sdio) ++static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio) + { + } + #endif /* CONFIG_OF */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -37,6 +37,8 @@ + #include "pcie.h" + #include "firmware.h" + #include "chip.h" ++#include "core.h" ++#include "common.h" + + + enum brcmf_pcie_state { +@@ -266,6 +268,7 @@ struct brcmf_pciedev_info { + u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset); + void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + u16 value); ++ struct brcmf_mp_device *settings; + }; + + struct brcmf_pcie_ringbuf { +@@ -1525,16 +1528,16 @@ static void brcmf_pcie_release_resource( + } + + +-static int brcmf_pcie_attach_bus(struct device *dev) ++static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo) + { + int ret; + + /* Attach to the common driver interface */ +- ret = brcmf_attach(dev); ++ ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings); + if (ret) { + brcmf_err("brcmf_attach failed\n"); + } else { +- ret = brcmf_bus_start(dev); ++ ret = brcmf_bus_start(&devinfo->pdev->dev); + if (ret) + brcmf_err("dongle is not responding\n"); + } +@@ -1672,7 +1675,7 @@ static void brcmf_pcie_setup(struct devi + init_waitqueue_head(&devinfo->mbdata_resp_wait); + + brcmf_pcie_intr_enable(devinfo); +- if (brcmf_pcie_attach_bus(bus->dev) == 0) ++ if (brcmf_pcie_attach_bus(devinfo) == 0) + return; + + brcmf_pcie_bus_console_read(devinfo); +@@ -1716,6 +1719,15 @@ brcmf_pcie_probe(struct pci_dev *pdev, c + goto fail; + } + ++ devinfo->settings = brcmf_get_module_param(&devinfo->pdev->dev, ++ BRCMF_BUSTYPE_PCIE, ++ devinfo->ci->chip, ++ devinfo->ci->chiprev); ++ if (!devinfo->settings) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) { + ret = -ENOMEM; +@@ -1760,6 +1772,8 @@ fail: + brcmf_pcie_release_resource(devinfo); + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); ++ if (devinfo->settings) ++ brcmf_release_module_param(devinfo->settings); + kfree(pcie_bus_dev); + kfree(devinfo); + return ret; +@@ -1799,6 +1813,8 @@ brcmf_pcie_remove(struct pci_dev *pdev) + + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); ++ if (devinfo->settings) ++ brcmf_release_module_param(devinfo->settings); + + kfree(devinfo); + dev_set_drvdata(&pdev->dev, NULL); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -2442,15 +2442,17 @@ static void brcmf_sdio_bus_stop(struct d + + static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) + { ++ struct brcmf_sdio_dev *sdiodev; + unsigned long flags; + +- if (bus->sdiodev->oob_irq_requested) { +- spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); +- if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) { +- enable_irq(bus->sdiodev->pdata->oob_irq_nr); +- bus->sdiodev->irq_en = true; ++ sdiodev = bus->sdiodev; ++ if (sdiodev->oob_irq_requested) { ++ spin_lock_irqsave(&sdiodev->irq_en_lock, flags); ++ if (!sdiodev->irq_en && !atomic_read(&bus->ipend)) { ++ enable_irq(sdiodev->settings->bus.sdio.oob_irq_nr); ++ sdiodev->irq_en = true; + } +- spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags); ++ spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); + } + } + +@@ -3394,9 +3396,7 @@ static int brcmf_sdio_bus_preinit(struct + sizeof(u32)); + } else { + /* otherwise, set txglomalign */ +- value = 4; +- if (sdiodev->pdata) +- value = sdiodev->pdata->sd_sgentry_align; ++ value = sdiodev->settings->bus.sdio.sd_sgentry_align; + /* SDIO ADMA requires at least 32 bit alignment */ + value = max_t(u32, value, 4); + err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value, +@@ -3811,21 +3811,25 @@ brcmf_sdio_probe_attach(struct brcmf_sdi + bus->ci = NULL; + goto fail; + } +- sdiodev->pdata = brcmf_get_module_param(sdiodev->dev, ++ sdiodev->settings = brcmf_get_module_param(sdiodev->dev, + BRCMF_BUSTYPE_SDIO, + bus->ci->chip, + bus->ci->chiprev); ++ if (!sdiodev->settings) { ++ brcmf_err("Failed to get device parameters\n"); ++ goto fail; ++ } + /* platform specific configuration: + * alignments must be at least 4 bytes for ADMA + */ + bus->head_align = ALIGNMENT; + bus->sgentry_align = ALIGNMENT; +- if (sdiodev->pdata) { +- if (sdiodev->pdata->sd_head_align > ALIGNMENT) +- bus->head_align = sdiodev->pdata->sd_head_align; +- if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) +- bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; +- } ++ if (sdiodev->settings->bus.sdio.sd_head_align > ALIGNMENT) ++ bus->head_align = sdiodev->settings->bus.sdio.sd_head_align; ++ if (sdiodev->settings->bus.sdio.sd_sgentry_align > ALIGNMENT) ++ bus->sgentry_align = ++ sdiodev->settings->bus.sdio.sd_sgentry_align; ++ + /* allocate scatter-gather table. sg support + * will be disabled upon allocation failure. + */ +@@ -3837,7 +3841,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi + */ + if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && + ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || +- (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) ++ (sdiodev->settings->bus.sdio.oob_irq_supported))) + sdiodev->bus_if->wowl_supported = true; + #endif + +@@ -3846,8 +3850,8 @@ brcmf_sdio_probe_attach(struct brcmf_sdi + goto fail; + } + +- if ((sdiodev->pdata) && (sdiodev->pdata->drive_strength)) +- drivestrength = sdiodev->pdata->drive_strength; ++ if (sdiodev->settings->bus.sdio.drive_strength) ++ drivestrength = sdiodev->settings->bus.sdio.drive_strength; + else + drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; + brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength); +@@ -4124,7 +4128,7 @@ struct brcmf_sdio *brcmf_sdio_probe(stru + bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; + + /* Attach to the common layer, reserve hdr space */ +- ret = brcmf_attach(bus->sdiodev->dev); ++ ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings); + if (ret != 0) { + brcmf_err("brcmf_attach failed\n"); + goto fail; +@@ -4228,6 +4232,8 @@ void brcmf_sdio_remove(struct brcmf_sdio + } + brcmf_chip_detach(bus->ci); + } ++ if (bus->sdiodev->settings) ++ brcmf_release_module_param(bus->sdiodev->settings); + + kfree(bus->rxbuf); + kfree(bus->hdrbuf); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -184,7 +184,7 @@ struct brcmf_sdio_dev { + struct brcmf_sdio *bus; + struct device *dev; + struct brcmf_bus *bus_if; +- struct brcmfmac_sdio_pd *pdata; ++ struct brcmf_mp_device *settings; + bool oob_irq_requested; + bool irq_en; /* irq enable flags */ + spinlock_t irq_en_lock; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -27,6 +27,8 @@ + #include "debug.h" + #include "firmware.h" + #include "usb.h" ++#include "core.h" ++#include "common.h" + + + #define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000) +@@ -171,6 +173,7 @@ struct brcmf_usbdev_info { + struct urb *bulk_urb; /* used for FW download */ + + bool wowl_enabled; ++ struct brcmf_mp_device *settings; + }; + + static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, +@@ -1027,6 +1030,9 @@ static void brcmf_usb_detach(struct brcm + + kfree(devinfo->tx_reqs); + kfree(devinfo->rx_reqs); ++ ++ if (devinfo->settings) ++ brcmf_release_module_param(devinfo->settings); + } + + +@@ -1136,7 +1142,7 @@ static int brcmf_usb_bus_setup(struct br + int ret; + + /* Attach to the common driver interface */ +- ret = brcmf_attach(devinfo->dev); ++ ret = brcmf_attach(devinfo->dev, devinfo->settings); + if (ret) { + brcmf_err("brcmf_attach failed\n"); + return ret; +@@ -1223,6 +1229,14 @@ static int brcmf_usb_probe_cb(struct brc + bus->wowl_supported = true; + #endif + ++ devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB, ++ bus_pub->devid, ++ bus_pub->chiprev); ++ if (!devinfo->settings) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ + if (!brcmf_usb_dlneeded(devinfo)) { + ret = brcmf_usb_bus_setup(devinfo); + if (ret) diff --git a/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch b/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch new file mode 100644 index 0000000000..eb680fccfc --- /dev/null +++ b/package/kernel/mac80211/patches/344-0019-brcmfmac-integrate-add_keyext-in-add_key.patch @@ -0,0 +1,227 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:09 +0100 +Subject: [PATCH] brcmfmac: integrate add_keyext in add_key + +brcmf_add_keyext is called when a key is configured for a specific +mac address. This function is very similar to the calling function +brcmf_add_key. Integrate this function and also use existing del_key +function in case key is to be cleared. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2073,84 +2073,34 @@ done: + } + + static s32 +-brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, +- u8 key_idx, const u8 *mac_addr, struct key_params *params) ++brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr) + { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_wsec_key key; + s32 err = 0; +- u8 keybuf[8]; ++ ++ brcmf_dbg(TRACE, "Enter\n"); ++ if (!check_vif_up(ifp->vif)) ++ return -EIO; ++ ++ if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { ++ /* we ignore this key index in this case */ ++ return -EINVAL; ++ } + + memset(&key, 0, sizeof(key)); +- key.index = (u32) key_idx; +- /* Instead of bcast for ea address for default wep keys, +- driver needs it to be Null */ +- if (!is_multicast_ether_addr(mac_addr)) +- memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); +- key.len = (u32) params->key_len; +- /* check for key index change */ +- if (key.len == 0) { +- /* key delete */ +- err = send_key_to_dongle(ifp, &key); +- if (err) +- brcmf_err("key delete error (%d)\n", err); +- } else { +- if (key.len > sizeof(key.data)) { +- brcmf_err("Invalid key length (%d)\n", key.len); +- return -EINVAL; +- } + +- brcmf_dbg(CONN, "Setting the key index %d\n", key.index); +- memcpy(key.data, params->key, key.len); ++ key.index = (u32)key_idx; ++ key.flags = BRCMF_PRIMARY_KEY; ++ key.algo = CRYPTO_ALGO_OFF; + +- if (!brcmf_is_apmode(ifp->vif) && +- (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { +- brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); +- memcpy(keybuf, &key.data[24], sizeof(keybuf)); +- memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); +- memcpy(&key.data[16], keybuf, sizeof(keybuf)); +- } ++ brcmf_dbg(CONN, "key index (%d)\n", key_idx); + +- /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ +- if (params->seq && params->seq_len == 6) { +- /* rx iv */ +- u8 *ivptr; +- ivptr = (u8 *) params->seq; +- key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | +- (ivptr[3] << 8) | ivptr[2]; +- key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; +- key.iv_initialized = true; +- } ++ /* Set the new key/index */ ++ err = send_key_to_dongle(ifp, &key); + +- switch (params->cipher) { +- case WLAN_CIPHER_SUITE_WEP40: +- key.algo = CRYPTO_ALGO_WEP1; +- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); +- break; +- case WLAN_CIPHER_SUITE_WEP104: +- key.algo = CRYPTO_ALGO_WEP128; +- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); +- break; +- case WLAN_CIPHER_SUITE_TKIP: +- key.algo = CRYPTO_ALGO_TKIP; +- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); +- break; +- case WLAN_CIPHER_SUITE_AES_CMAC: +- key.algo = CRYPTO_ALGO_AES_CCM; +- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); +- break; +- case WLAN_CIPHER_SUITE_CCMP: +- key.algo = CRYPTO_ALGO_AES_CCM; +- brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); +- break; +- default: +- brcmf_err("Invalid cipher (0x%x)\n", params->cipher); +- return -EINVAL; +- } +- err = send_key_to_dongle(ifp, &key); +- if (err) +- brcmf_err("wsec_key error (%d)\n", err); +- } ++ brcmf_dbg(TRACE, "Exit\n"); + return err; + } + +@@ -2163,8 +2113,9 @@ brcmf_cfg80211_add_key(struct wiphy *wip + struct brcmf_wsec_key *key; + s32 val; + s32 wsec; +- s32 err = 0; ++ s32 err; + u8 keybuf[8]; ++ bool ext_key; + + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CONN, "key index (%d)\n", key_idx); +@@ -2177,27 +2128,32 @@ brcmf_cfg80211_add_key(struct wiphy *wip + return -EINVAL; + } + +- if (mac_addr && +- (params->cipher != WLAN_CIPHER_SUITE_WEP40) && +- (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { +- brcmf_dbg(TRACE, "Exit"); +- return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); +- } +- +- key = &ifp->vif->profile.key[key_idx]; +- memset(key, 0, sizeof(*key)); ++ if (params->key_len == 0) ++ return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise, ++ mac_addr); + + if (params->key_len > sizeof(key->data)) { + brcmf_err("Too long key length (%u)\n", params->key_len); +- err = -EINVAL; +- goto done; ++ return -EINVAL; ++ } ++ ++ ext_key = false; ++ if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) && ++ (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { ++ brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr); ++ ext_key = true; + } ++ ++ key = &ifp->vif->profile.key[key_idx]; ++ memset(key, 0, sizeof(*key)); ++ if ((ext_key) && (!is_multicast_ether_addr(mac_addr))) ++ memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN); + key->len = params->key_len; + key->index = key_idx; +- + memcpy(key->data, params->key, key->len); ++ if (!ext_key) ++ key->flags = BRCMF_PRIMARY_KEY; + +- key->flags = BRCMF_PRIMARY_KEY; + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key->algo = CRYPTO_ALGO_WEP1; +@@ -2237,7 +2193,7 @@ brcmf_cfg80211_add_key(struct wiphy *wip + } + + err = send_key_to_dongle(ifp, key); +- if (err) ++ if (ext_key || err) + goto done; + + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); +@@ -2256,38 +2212,6 @@ done: + brcmf_dbg(TRACE, "Exit\n"); + return err; + } +- +-static s32 +-brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, +- u8 key_idx, bool pairwise, const u8 *mac_addr) +-{ +- struct brcmf_if *ifp = netdev_priv(ndev); +- struct brcmf_wsec_key key; +- s32 err = 0; +- +- brcmf_dbg(TRACE, "Enter\n"); +- if (!check_vif_up(ifp->vif)) +- return -EIO; +- +- if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { +- /* we ignore this key index in this case */ +- return -EINVAL; +- } +- +- memset(&key, 0, sizeof(key)); +- +- key.index = (u32) key_idx; +- key.flags = BRCMF_PRIMARY_KEY; +- key.algo = CRYPTO_ALGO_OFF; +- +- brcmf_dbg(CONN, "key index (%d)\n", key_idx); +- +- /* Set the new key/index */ +- err = send_key_to_dongle(ifp, &key); +- +- brcmf_dbg(TRACE, "Exit\n"); +- return err; +-} + + static s32 + brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, diff --git a/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch b/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch new file mode 100644 index 0000000000..c20d40c049 --- /dev/null +++ b/package/kernel/mac80211/patches/344-0020-brcmfmac-add-802.11w-management-frame-protection-sup.patch @@ -0,0 +1,509 @@ +From: Hante Meuleman +Date: Wed, 17 Feb 2016 11:27:10 +0100 +Subject: [PATCH] brcmfmac: add 802.11w management frame protection support + +Add full support for both AP and STA for management frame protection. + +Reviewed-by: Arend Van Spriel +Reviewed-by: Franky (Zhenhui) Lin +Reviewed-by: Pieter-Paul Giesberts +Signed-off-by: Hante Meuleman +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -72,8 +72,13 @@ + #define RSN_AKM_NONE 0 /* None (IBSS) */ + #define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ + #define RSN_AKM_PSK 2 /* Pre-shared Key */ ++#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */ ++#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */ + #define RSN_CAP_LEN 2 /* Length of RSN capabilities */ +-#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C ++#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3)) ++#define RSN_CAP_MFPR_MASK BIT(6) ++#define RSN_CAP_MFPC_MASK BIT(7) ++#define RSN_PMKID_COUNT_LEN 2 + + #define VNDR_IE_CMD_LEN 4 /* length of the set command + * string :"add", "del" (+ NUL) +@@ -211,12 +216,19 @@ static const struct ieee80211_regdomain + REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), } + }; + +-static const u32 __wl_cipher_suites[] = { ++/* Note: brcmf_cipher_suites is an array of int defining which cipher suites ++ * are supported. A pointer to this array and the number of entries is passed ++ * on to upper layers. AES_CMAC defines whether or not the driver supports MFP. ++ * So the cipher suite AES_CMAC has to be the last one in the array, and when ++ * device does not support MFP then the number of suites will be decreased by 1 ++ */ ++static const u32 brcmf_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +- WLAN_CIPHER_SUITE_AES_CMAC, ++ /* Keep as last entry: */ ++ WLAN_CIPHER_SUITE_AES_CMAC + }; + + /* Vendor specific ie. id = 221, oui and type defines exact ie */ +@@ -1533,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct ne + + static s32 + brcmf_set_wsec_mode(struct net_device *ndev, +- struct cfg80211_connect_params *sme, bool mfp) ++ struct cfg80211_connect_params *sme) + { + struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); + struct brcmf_cfg80211_security *sec; +@@ -1592,10 +1604,7 @@ brcmf_set_wsec_mode(struct net_device *n + sme->privacy) + pval = AES_ENABLED; + +- if (mfp) +- wsec = pval | gval | MFP_CAPABLE; +- else +- wsec = pval | gval; ++ wsec = pval | gval; + err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec); + if (err) { + brcmf_err("error (%d)\n", err); +@@ -1612,56 +1621,100 @@ brcmf_set_wsec_mode(struct net_device *n + static s32 + brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) + { +- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); +- struct brcmf_cfg80211_security *sec; +- s32 val = 0; +- s32 err = 0; ++ struct brcmf_if *ifp = netdev_priv(ndev); ++ s32 val; ++ s32 err; ++ const struct brcmf_tlv *rsn_ie; ++ const u8 *ie; ++ u32 ie_len; ++ u32 offset; ++ u16 rsn_cap; ++ u32 mfp; ++ u16 count; + +- if (sme->crypto.n_akm_suites) { +- err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), +- "wpa_auth", &val); +- if (err) { +- brcmf_err("could not get wpa_auth (%d)\n", err); +- return err; ++ if (!sme->crypto.n_akm_suites) ++ return 0; ++ ++ err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val); ++ if (err) { ++ brcmf_err("could not get wpa_auth (%d)\n", err); ++ return err; ++ } ++ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA_AUTH_PSK; ++ break; ++ default: ++ brcmf_err("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; + } +- if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { +- switch (sme->crypto.akm_suites[0]) { +- case WLAN_AKM_SUITE_8021X: +- val = WPA_AUTH_UNSPECIFIED; +- break; +- case WLAN_AKM_SUITE_PSK: +- val = WPA_AUTH_PSK; +- break; +- default: +- brcmf_err("invalid cipher group (%d)\n", +- sme->crypto.cipher_group); +- return -EINVAL; +- } +- } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { +- switch (sme->crypto.akm_suites[0]) { +- case WLAN_AKM_SUITE_8021X: +- val = WPA2_AUTH_UNSPECIFIED; +- break; +- case WLAN_AKM_SUITE_PSK: +- val = WPA2_AUTH_PSK; +- break; +- default: +- brcmf_err("invalid cipher group (%d)\n", +- sme->crypto.cipher_group); +- return -EINVAL; +- } ++ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_8021X_SHA256: ++ val = WPA2_AUTH_1X_SHA256; ++ break; ++ case WLAN_AKM_SUITE_PSK_SHA256: ++ val = WPA2_AUTH_PSK_SHA256; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA2_AUTH_PSK; ++ break; ++ default: ++ brcmf_err("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; + } ++ } + +- brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); +- err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), +- "wpa_auth", val); +- if (err) { +- brcmf_err("could not set wpa_auth (%d)\n", err); +- return err; +- } ++ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) ++ goto skip_mfp_config; ++ /* The MFP mode (1 or 2) needs to be determined, parse IEs. The ++ * IE will not be verified, just a quick search for MFP config ++ */ ++ rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len, ++ WLAN_EID_RSN); ++ if (!rsn_ie) ++ goto skip_mfp_config; ++ ie = (const u8 *)rsn_ie; ++ ie_len = rsn_ie->len + TLV_HDR_LEN; ++ /* Skip unicast suite */ ++ offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN; ++ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len) ++ goto skip_mfp_config; ++ /* Skip multicast suite */ ++ count = ie[offset] + (ie[offset + 1] << 8); ++ offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN); ++ if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len) ++ goto skip_mfp_config; ++ /* Skip auth key management suite(s) */ ++ count = ie[offset] + (ie[offset + 1] << 8); ++ offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN); ++ if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len) ++ goto skip_mfp_config; ++ /* Ready to read capabilities */ ++ mfp = BRCMF_MFP_NONE; ++ rsn_cap = ie[offset] + (ie[offset + 1] << 8); ++ if (rsn_cap & RSN_CAP_MFPR_MASK) ++ mfp = BRCMF_MFP_REQUIRED; ++ else if (rsn_cap & RSN_CAP_MFPC_MASK) ++ mfp = BRCMF_MFP_CAPABLE; ++ brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp); ++ ++skip_mfp_config: ++ brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); ++ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); ++ if (err) { ++ brcmf_err("could not set wpa_auth (%d)\n", err); ++ return err; + } +- sec = &profile->sec; +- sec->wpa_auth = sme->crypto.akm_suites[0]; + + return err; + } +@@ -1827,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wip + goto done; + } + +- err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED); ++ err = brcmf_set_wsec_mode(ndev, sme); + if (err) { + brcmf_err("wl_set_set_cipher failed (%d)\n", err); + goto done; +@@ -2077,10 +2130,12 @@ brcmf_cfg80211_del_key(struct wiphy *wip + u8 key_idx, bool pairwise, const u8 *mac_addr) + { + struct brcmf_if *ifp = netdev_priv(ndev); +- struct brcmf_wsec_key key; +- s32 err = 0; ++ struct brcmf_wsec_key *key; ++ s32 err; + + brcmf_dbg(TRACE, "Enter\n"); ++ brcmf_dbg(CONN, "key index (%d)\n", key_idx); ++ + if (!check_vif_up(ifp->vif)) + return -EIO; + +@@ -2089,16 +2144,19 @@ brcmf_cfg80211_del_key(struct wiphy *wip + return -EINVAL; + } + +- memset(&key, 0, sizeof(key)); ++ key = &ifp->vif->profile.key[key_idx]; + +- key.index = (u32)key_idx; +- key.flags = BRCMF_PRIMARY_KEY; +- key.algo = CRYPTO_ALGO_OFF; ++ if (key->algo == CRYPTO_ALGO_OFF) { ++ brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n"); ++ return -EINVAL; ++ } + +- brcmf_dbg(CONN, "key index (%d)\n", key_idx); ++ memset(key, 0, sizeof(*key)); ++ key->index = (u32)key_idx; ++ key->flags = BRCMF_PRIMARY_KEY; + +- /* Set the new key/index */ +- err = send_key_to_dongle(ifp, &key); ++ /* Clear the key/index */ ++ err = send_key_to_dongle(ifp, key); + + brcmf_dbg(TRACE, "Exit\n"); + return err; +@@ -2106,8 +2164,8 @@ brcmf_cfg80211_del_key(struct wiphy *wip + + static s32 + brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, +- u8 key_idx, bool pairwise, const u8 *mac_addr, +- struct key_params *params) ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) + { + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_wsec_key *key; +@@ -2214,9 +2272,10 @@ done: + } + + static s32 +-brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, +- u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, +- void (*callback) (void *cookie, struct key_params * params)) ++brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, ++ bool pairwise, const u8 *mac_addr, void *cookie, ++ void (*callback)(void *cookie, ++ struct key_params *params)) + { + struct key_params params; + struct brcmf_if *ifp = netdev_priv(ndev); +@@ -2268,8 +2327,15 @@ done: + + static s32 + brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, +- struct net_device *ndev, u8 key_idx) ++ struct net_device *ndev, u8 key_idx) + { ++ struct brcmf_if *ifp = netdev_priv(ndev); ++ ++ brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx); ++ ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) ++ return 0; ++ + brcmf_dbg(INFO, "Not supported\n"); + + return -EOPNOTSUPP; +@@ -3769,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *i + u32 auth = 0; /* d11 open authentication */ + u16 count; + s32 err = 0; +- s32 len = 0; ++ s32 len; + u32 i; + u32 wsec; + u32 pval = 0; +@@ -3779,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *i + u8 *data; + u16 rsn_cap; + u32 wme_bss_disable; ++ u32 mfp; + + brcmf_dbg(TRACE, "Enter\n"); + if (wpa_ie == NULL) +@@ -3893,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *i + is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) : + (wpa_auth |= WPA_AUTH_PSK); + break; ++ case RSN_AKM_SHA256_PSK: ++ brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n"); ++ wpa_auth |= WPA2_AUTH_PSK_SHA256; ++ break; ++ case RSN_AKM_SHA256_1X: ++ brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n"); ++ wpa_auth |= WPA2_AUTH_1X_SHA256; ++ break; + default: + brcmf_err("Ivalid key mgmt info\n"); + } + offset++; + } + ++ mfp = BRCMF_MFP_NONE; + if (is_rsn_ie) { + wme_bss_disable = 1; + if ((offset + RSN_CAP_LEN) <= len) { + rsn_cap = data[offset] + (data[offset + 1] << 8); + if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK) + wme_bss_disable = 0; ++ if (rsn_cap & RSN_CAP_MFPR_MASK) { ++ brcmf_dbg(TRACE, "MFP Required\n"); ++ mfp = BRCMF_MFP_REQUIRED; ++ /* Firmware only supports mfp required in ++ * combination with WPA2_AUTH_PSK_SHA256 or ++ * WPA2_AUTH_1X_SHA256. ++ */ ++ if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 | ++ WPA2_AUTH_1X_SHA256))) { ++ err = -EINVAL; ++ goto exit; ++ } ++ /* Firmware has requirement that WPA2_AUTH_PSK/ ++ * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI ++ * is to be included in the rsn ie. ++ */ ++ if (wpa_auth & WPA2_AUTH_PSK_SHA256) ++ wpa_auth |= WPA2_AUTH_PSK; ++ else if (wpa_auth & WPA2_AUTH_1X_SHA256) ++ wpa_auth |= WPA2_AUTH_UNSPECIFIED; ++ } else if (rsn_cap & RSN_CAP_MFPC_MASK) { ++ brcmf_dbg(TRACE, "MFP Capable\n"); ++ mfp = BRCMF_MFP_CAPABLE; ++ } + } ++ offset += RSN_CAP_LEN; + /* set wme_bss_disable to sync RSN Capabilities */ + err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable", + wme_bss_disable); +@@ -3913,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *i + brcmf_err("wme_bss_disable error %d\n", err); + goto exit; + } ++ ++ /* Skip PMKID cnt as it is know to be 0 for AP. */ ++ offset += RSN_PMKID_COUNT_LEN; ++ ++ /* See if there is BIP wpa suite left for MFP */ ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) && ++ ((offset + WPA_IE_MIN_OUI_LEN) <= len)) { ++ err = brcmf_fil_bsscfg_data_set(ifp, "bip", ++ &data[offset], ++ WPA_IE_MIN_OUI_LEN); ++ if (err < 0) { ++ brcmf_err("bip error %d\n", err); ++ goto exit; ++ } ++ } + } + /* FOR WPS , set SES_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); +@@ -3929,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *i + brcmf_err("wsec error %d\n", err); + goto exit; + } ++ /* Configure MFP, this needs to go after wsec otherwise the wsec command ++ * will overwrite the values set by MFP ++ */ ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) { ++ err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp); ++ if (err < 0) { ++ brcmf_err("mfp error %d\n", err); ++ goto exit; ++ } ++ } + /* set upper-layer auth */ + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth); + if (err < 0) { +@@ -6149,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiph + wiphy->n_addresses = i; + + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; +- wiphy->cipher_suites = __wl_cipher_suites; +- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); ++ wiphy->cipher_suites = brcmf_cipher_suites; ++ wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites); ++ if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) ++ wiphy->n_cipher_suites--; + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | + WIPHY_FLAG_OFFCHAN_TX | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +@@ -72,7 +72,7 @@ + + #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 + +-#define BRCMF_MAX_DEFAULT_KEYS 4 ++#define BRCMF_MAX_DEFAULT_KEYS 6 + + /* beacon loss timeout defaults */ + #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2 +@@ -107,7 +107,6 @@ struct brcmf_cfg80211_security { + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; +- u32 wpa_auth; + }; + + /** +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +@@ -161,6 +161,7 @@ void brcmf_feat_attach(struct brcmf_pub + ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode"); + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable"); ++ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp"); + + pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; + err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac, +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +@@ -30,6 +30,7 @@ + * WOWL_ND: WOWL net detect (PNO) + * WOWL_GTK: (WOWL) GTK rekeying offload + * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. ++ * MFP: 802.11w Management Frame Protection. + */ + #define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MBSS) \ +@@ -42,7 +43,8 @@ + BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \ + BRCMF_FEAT_DEF(WOWL_ND) \ + BRCMF_FEAT_DEF(WOWL_GTK) \ +- BRCMF_FEAT_DEF(WOWL_ARP_ND) ++ BRCMF_FEAT_DEF(WOWL_ARP_ND) \ ++ BRCMF_FEAT_DEF(MFP) + + /* + * Quirks: +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +@@ -142,6 +142,10 @@ + #define BRCMF_RSN_KEK_LENGTH 16 + #define BRCMF_RSN_REPLAY_LEN 8 + ++#define BRCMF_MFP_NONE 0 ++#define BRCMF_MFP_CAPABLE 1 ++#define BRCMF_MFP_REQUIRED 2 ++ + /* join preference types for join_pref iovar */ + enum brcmf_join_pref_types { + BRCMF_JOIN_PREF_RSSI = 1, +--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +@@ -236,6 +236,8 @@ static inline bool ac_bitmap_tst(u8 bitm + #define WPA2_AUTH_RESERVED3 0x0200 + #define WPA2_AUTH_RESERVED4 0x0400 + #define WPA2_AUTH_RESERVED5 0x0800 ++#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */ ++#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ + + #define DOT11_DEFAULT_RTS_LEN 2347 + #define DOT11_DEFAULT_FRAG_LEN 2346 diff --git a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch index 95d93ae1f6..7803733fda 100644 --- a/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/861-brcmfmac-register-wiphy-s-during-module_init.patch @@ -13,8 +13,8 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -1332,6 +1332,7 @@ static int __init brcmfmac_module_init(v - #endif +@@ -1417,6 +1417,7 @@ int __init brcmf_core_init(void) + { if (!schedule_work(&brcmf_driver_work)) return -EBUSY; + flush_work(&brcmf_driver_work); diff --git a/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch index 4295b4bd33..ac0f704538 100644 --- a/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch +++ b/package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch @@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -615,9 +615,37 @@ static struct wireless_dev *brcmf_cfg802 +@@ -636,9 +636,37 @@ static struct wireless_dev *brcmf_cfg802 u32 *flags, struct vif_params *params) { -- 2.30.2