diff options
Diffstat (limited to 'drivers/net/wireless/broadcom')
23 files changed, 655 insertions, 363 deletions
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 6e5d9095b195..52f3541ecbcf 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -5591,7 +5591,9 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_WIRELESS_WDS BIT(NL80211_IFTYPE_WDS) | +#endif BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 83770d2ea057..e97ab2b91663 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -3838,7 +3838,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_WIRELESS_WDS BIT(NL80211_IFTYPE_WDS) | +#endif BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ hw->max_rates = 2; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index 9e4b505ca593..d1568bed1ad1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -35,7 +35,8 @@ brcmfmac-objs += \ firmware.o \ feature.o \ btcoex.o \ - vendor.o + vendor.o \ + pno.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \ bcdc.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 038a960c5104..384b1873e7e3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -326,6 +326,17 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, return 0; } +static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *skb) +{ + struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx); + + if (!brcmf_fws_queue_skbs(drvr->fws)) + return brcmf_proto_txdata(drvr, ifidx, 0, skb); + + return brcmf_fws_process_skb(ifp, skb); +} + static int brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *pktbuf) @@ -375,6 +386,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; + drvr->proto->tx_queue_data = brcmf_proto_bcdc_tx_queue_data; drvr->proto->txdata = brcmf_proto_bcdc_txdata; drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 2b246545647a..e21f7600122b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -22,10 +22,12 @@ /* IDs of the 6 default common rings of msgbuf protocol */ #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0 #define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1 +#define BRCMF_H2D_MSGRING_FLOWRING_IDSTART 2 #define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2 #define BRCMF_D2H_MSGRING_TX_COMPLETE 3 #define BRCMF_D2H_MSGRING_RX_COMPLETE 4 + #define BRCMF_NROF_H2D_COMMON_MSGRINGS 2 #define BRCMF_NROF_D2H_COMMON_MSGRINGS 3 #define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \ @@ -95,14 +97,18 @@ struct brcmf_bus_ops { * @flowrings: commonrings which are dynamically created and destroyed for data. * @rx_dataoffset: if set then all rx data has this this offset. * @max_rxbufpost: maximum number of buffers to post for rx. - * @nrof_flowrings: number of flowrings. + * @max_flowrings: maximum number of tx flow rings supported. + * @max_submissionrings: maximum number of submission rings(h2d) supported. + * @max_completionrings: maximum number of completion rings(d2h) supported. */ struct brcmf_bus_msgbuf { struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; struct brcmf_commonring **flowrings; u32 rx_dataoffset; u32 max_rxbufpost; - u32 nrof_flowrings; + u16 max_flowrings; + u16 max_submissionrings; + u16 max_completionrings; }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b777e1b2f87a..ccae3bbe7db2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -32,6 +32,7 @@ #include "fwil_types.h" #include "p2p.h" #include "btcoex.h" +#include "pno.h" #include "cfg80211.h" #include "feature.h" #include "fwil.h" @@ -41,16 +42,6 @@ #include "common.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 -#define BRCMF_PNO_VERSION 2 -#define BRCMF_PNO_TIME 30 -#define BRCMF_PNO_REPEAT 4 -#define BRCMF_PNO_FREQ_EXPO_MAX 3 -#define BRCMF_PNO_MAX_PFN_COUNT 16 -#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 -#define BRCMF_PNO_HIDDEN_BIT 2 -#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF -#define BRCMF_PNO_SCAN_COMPLETE 1 -#define BRCMF_PNO_SCAN_INCOMPLETE 0 #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ #define WPA_OUI_TYPE 1 @@ -414,23 +405,24 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *vif, enum nl80211_iftype new_type) { - int iftype_num[NUM_NL80211_IFTYPES]; struct brcmf_cfg80211_vif *pos; bool check_combos = false; int ret = 0; + struct iface_combination_params params = { + .num_different_channels = 1, + }; - memset(&iftype_num[0], 0, sizeof(iftype_num)); list_for_each_entry(pos, &cfg->vif_list, list) if (pos == vif) { - iftype_num[new_type]++; + params.iftype_num[new_type]++; } else { /* concurrent interfaces so need check combinations */ check_combos = true; - iftype_num[pos->wdev.iftype]++; + params.iftype_num[pos->wdev.iftype]++; } if (check_combos) - ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); + ret = cfg80211_check_combinations(cfg->wiphy, ¶ms); return ret; } @@ -438,15 +430,16 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype new_type) { - int iftype_num[NUM_NL80211_IFTYPES]; struct brcmf_cfg80211_vif *pos; + struct iface_combination_params params = { + .num_different_channels = 1, + }; - memset(&iftype_num[0], 0, sizeof(iftype_num)); list_for_each_entry(pos, &cfg->vif_list, list) - iftype_num[pos->wdev.iftype]++; + params.iftype_num[pos->wdev.iftype]++; - iftype_num[new_type]++; - return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); + params.iftype_num[new_type]++; + return cfg80211_check_combinations(cfg->wiphy, ¶ms); } static void convert_key_from_CPU(struct brcmf_wsec_key *key, @@ -766,12 +759,12 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, brcmf_scan_config_mpc(ifp, 1); /* - * e-scan can be initiated by scheduled scan + * e-scan can be initiated internally * which takes precedence. */ - if (cfg->sched_escan) { + if (cfg->internal_escan) { brcmf_dbg(SCAN, "scheduled scan completed\n"); - cfg->sched_escan = false; + cfg->internal_escan = false; if (!aborted) cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); } else if (scan_request) { @@ -1089,9 +1082,9 @@ exit: } static s32 -brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, - struct brcmf_if *ifp, struct cfg80211_scan_request *request) +brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request) { + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 err; u32 passive_scan; struct brcmf_scan_results *results; @@ -1099,7 +1092,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, brcmf_dbg(SCAN, "Enter\n"); escan->ifp = ifp; - escan->wiphy = wiphy; + escan->wiphy = cfg->wiphy; escan->escan_state = WL_ESCAN_STATE_SCANNING; passive_scan = cfg->active_scan ? 0 : 1; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, @@ -1179,7 +1172,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, if (err) goto scan_out; - err = brcmf_do_escan(cfg, wiphy, vif->ifp, request); + err = brcmf_do_escan(vif->ifp, request); if (err) goto scan_out; } else { @@ -3022,7 +3015,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) struct escan_info *escan = &cfg->escan_info; set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); - if (cfg->scan_request) { + if (cfg->internal_escan || cfg->scan_request) { escan->escan_state = WL_ESCAN_STATE_IDLE; brcmf_notify_escan_complete(cfg, escan->ifp, true, true); } @@ -3045,7 +3038,7 @@ static void brcmf_escan_timeout(unsigned long data) struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)data; - if (cfg->scan_request) { + if (cfg->internal_escan || cfg->scan_request) { brcmf_err("timer expired\n"); schedule_work(&cfg->escan_timeout_work); } @@ -3128,7 +3121,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) goto exit; - if (!cfg->scan_request) { + if (!cfg->internal_escan && !cfg->scan_request) { brcmf_dbg(SCAN, "result without cfg80211 request\n"); goto exit; } @@ -3174,7 +3167,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) goto exit; - if (cfg->scan_request) { + if (cfg->internal_escan || cfg->scan_request) { brcmf_inform_bss(cfg); aborted = status != BRCMF_E_STATUS_SUCCESS; brcmf_notify_escan_complete(cfg, ifp, aborted, false); @@ -3199,6 +3192,95 @@ static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) brcmf_cfg80211_escan_timeout_worker); } +static struct cfg80211_scan_request * +brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) { + struct cfg80211_scan_request *req; + size_t req_size; + + req_size = sizeof(*req) + + n_netinfo * sizeof(req->channels[0]) + + n_netinfo * sizeof(*req->ssids); + + req = kzalloc(req_size, GFP_KERNEL); + if (req) { + req->wiphy = wiphy; + req->ssids = (void *)(&req->channels[0]) + + n_netinfo * sizeof(req->channels[0]); + } + return req; +} + +static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, + u8 *ssid, u8 ssid_len, u8 channel) +{ + struct ieee80211_channel *chan; + enum nl80211_band band; + int freq; + + if (channel <= CH_MAX_2G_CHANNEL) + band = NL80211_BAND_2GHZ; + else + band = NL80211_BAND_5GHZ; + + freq = ieee80211_channel_to_frequency(channel, band); + if (!freq) + return -EINVAL; + + chan = ieee80211_get_channel(req->wiphy, freq); + if (!chan) + return -EINVAL; + + req->channels[req->n_channels++] = chan; + memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len); + req->ssids[req->n_ssids++].ssid_len = ssid_len; + + return 0; +} + +static int brcmf_start_internal_escan(struct brcmf_if *ifp, + struct cfg80211_scan_request *request) +{ + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + int err; + + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + /* Abort any on-going scan */ + brcmf_abort_scanning(cfg); + } + + set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); + cfg->escan_info.run = brcmf_run_escan; + err = brcmf_do_escan(ifp, request); + if (err) { + clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); + return err; + } + cfg->internal_escan = true; + return 0; +} + +static struct brcmf_pno_net_info_le * +brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1) +{ + struct brcmf_pno_scanresults_v2_le *pfn_v2; + struct brcmf_pno_net_info_le *netinfo; + + switch (pfn_v1->version) { + default: + WARN_ON(1); + /* fall-thru */ + case cpu_to_le32(1): + netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1); + break; + case cpu_to_le32(2): + pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1; + netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1); + break; + } + + return netinfo; +} + /* PFN result doesn't have all the info which are required by the supplicant * (For e.g IEs) Do a target Escan so that sched scan results are reported * via wl_inform_single_bss in the required format. Escan does require the @@ -3212,12 +3294,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct brcmf_pno_net_info_le *netinfo, *netinfo_start; struct cfg80211_scan_request *request = NULL; - struct cfg80211_ssid *ssid = NULL; - struct ieee80211_channel *channel = NULL; struct wiphy *wiphy = cfg_to_wiphy(cfg); - int err = 0; - int channel_req = 0; - int band = 0; + int i, err = 0; struct brcmf_pno_scanresults_le *pfn_result; u32 result_count; u32 status; @@ -3243,254 +3321,86 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, */ WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count); - if (result_count > 0) { - int i; - - request = kzalloc(sizeof(*request), GFP_KERNEL); - ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL); - channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL); - if (!request || !ssid || !channel) { - err = -ENOMEM; - goto out_err; - } - - request->wiphy = wiphy; - data += sizeof(struct brcmf_pno_scanresults_le); - netinfo_start = (struct brcmf_pno_net_info_le *)data; - - for (i = 0; i < result_count; i++) { - netinfo = &netinfo_start[i]; - if (!netinfo) { - brcmf_err("Invalid netinfo ptr. index: %d\n", - i); - err = -EINVAL; - goto out_err; - } - - brcmf_dbg(SCAN, "SSID:%s Channel:%d\n", - netinfo->SSID, netinfo->channel); - memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); - ssid[i].ssid_len = netinfo->SSID_len; - request->n_ssids++; - - channel_req = netinfo->channel; - if (channel_req <= CH_MAX_2G_CHANNEL) - band = NL80211_BAND_2GHZ; - else - band = NL80211_BAND_5GHZ; - channel[i].center_freq = - ieee80211_channel_to_frequency(channel_req, - band); - channel[i].band = band; - channel[i].flags |= IEEE80211_CHAN_NO_HT40; - request->channels[i] = &channel[i]; - request->n_channels++; - } - - /* assign parsed ssid array */ - if (request->n_ssids) - request->ssids = &ssid[0]; - - if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - /* Abort any on-going scan */ - brcmf_abort_scanning(cfg); - } - - set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); - cfg->escan_info.run = brcmf_run_escan; - err = brcmf_do_escan(cfg, wiphy, ifp, request); - if (err) { - clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); - goto out_err; - } - cfg->sched_escan = true; - cfg->scan_request = request; - } else { + if (!result_count) { brcmf_err("FALSE PNO Event. (pfn_count == 0)\n"); goto out_err; } - - kfree(ssid); - kfree(channel); - kfree(request); - return 0; - -out_err: - kfree(ssid); - kfree(channel); - kfree(request); - cfg80211_sched_scan_stopped(wiphy); - return err; -} - -static int brcmf_dev_pno_clean(struct net_device *ndev) -{ - int ret; - - /* Disable pfn */ - ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0); - if (ret == 0) { - /* clear pfn */ - ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear", - NULL, 0); - } - if (ret < 0) - brcmf_err("failed code %d\n", ret); - - return ret; -} - -static int brcmf_dev_pno_config(struct brcmf_if *ifp, - struct cfg80211_sched_scan_request *request) -{ - struct brcmf_pno_param_le pfn_param; - struct brcmf_pno_macaddr_le pfn_mac; - s32 err; - u8 *mac_mask; - int i; - - memset(&pfn_param, 0, sizeof(pfn_param)); - pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); - - /* set extra pno params */ - pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = BRCMF_PNO_REPEAT; - pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; - - /* set up pno scan fr */ - pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); - - err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param, - sizeof(pfn_param)); - if (err) { - brcmf_err("pfn_set failed, err=%d\n", err); - return err; + request = brcmf_alloc_internal_escan_request(wiphy, + result_count); + if (!request) { + err = -ENOMEM; + goto out_err; } - /* Find out if mac randomization should be turned on */ - if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) - return 0; + data += sizeof(struct brcmf_pno_scanresults_le); + netinfo_start = brcmf_get_netinfo_array(pfn_result); - pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; - pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; + for (i = 0; i < result_count; i++) { + netinfo = &netinfo_start[i]; + if (!netinfo) { + brcmf_err("Invalid netinfo ptr. index: %d\n", + i); + err = -EINVAL; + goto out_err; + } - memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN); - mac_mask = request->mac_addr_mask; - for (i = 0; i < ETH_ALEN; i++) { - pfn_mac.mac[i] &= mac_mask[i]; - pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]); + brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n", + netinfo->SSID, netinfo->channel); + err = brcmf_internal_escan_add_info(request, + netinfo->SSID, + netinfo->SSID_len, + netinfo->channel); + if (err) + goto out_err; } - /* Clear multi bit */ - pfn_mac.mac[0] &= 0xFE; - /* Set locally administered */ - pfn_mac.mac[0] |= 0x02; - err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, - sizeof(pfn_mac)); - if (err) - brcmf_err("pfn_macaddr failed, err=%d\n", err); + err = brcmf_start_internal_escan(ifp, request); + if (!err) + goto free_req; +out_err: + cfg80211_sched_scan_stopped(wiphy); +free_req: + kfree(request); return err; } static int brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_sched_scan_request *request) + struct cfg80211_sched_scan_request *req) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - struct brcmf_pno_net_param_le pfn; - int i; - int ret = 0; brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", - request->n_match_sets, request->n_ssids); - if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { - brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status); - return -EAGAIN; - } + req->n_match_sets, req->n_ssids); + if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { brcmf_err("Scanning suppressed: status (%lu)\n", cfg->scan_status); return -EAGAIN; } - if (!request->n_ssids || !request->n_match_sets) { - brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n", - request->n_ssids); - return -EINVAL; - } - - if (request->n_ssids > 0) { - for (i = 0; i < request->n_ssids; i++) { - /* Active scan req for ssids */ - brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n", - request->ssids[i].ssid); - - /* match_set ssids is a supert set of n_ssid list, - * so we need not add these set separately. - */ - } - } - - if (request->n_match_sets > 0) { - /* clean up everything */ - ret = brcmf_dev_pno_clean(ndev); - if (ret < 0) { - brcmf_err("failed error=%d\n", ret); - return ret; - } - - /* configure pno */ - if (brcmf_dev_pno_config(ifp, request)) - return -EINVAL; - - /* configure each match set */ - for (i = 0; i < request->n_match_sets; i++) { - struct cfg80211_ssid *ssid; - u32 ssid_len; - - ssid = &request->match_sets[i].ssid; - ssid_len = ssid->ssid_len; - - if (!ssid_len) { - brcmf_err("skip broadcast ssid\n"); - continue; - } - pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); - pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); - pfn.wsec = cpu_to_le32(0); - pfn.infra = cpu_to_le32(1); - pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); - pfn.ssid.SSID_len = cpu_to_le32(ssid_len); - memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); - ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, - sizeof(pfn)); - brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", - ret == 0 ? "set" : "failed", ssid->ssid); - } - /* Enable the PNO */ - if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) { - brcmf_err("PNO enable failed!! ret=%d\n", ret); - return -EINVAL; - } - } else { + if (req->n_match_sets <= 0) { + brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n", + req->n_match_sets); return -EINVAL; } - return 0; + return brcmf_pno_start_sched_scan(ifp, req); } static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = netdev_priv(ndev); brcmf_dbg(SCAN, "enter\n"); - brcmf_dev_pno_clean(ndev); - if (cfg->sched_escan) - brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true); + brcmf_pno_clean(ifp); + if (cfg->internal_escan) + brcmf_notify_escan_complete(cfg, ifp, true, true); return 0; } @@ -4516,7 +4426,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, /* store current 11d setting */ if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d)) { - supports_11d = false; + is_11d = supports_11d = false; } else { country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, settings->beacon.tail_len, @@ -4578,8 +4488,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_configure_opensecurity(ifp); } - brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); - /* Parameters shared by all radio interfaces */ if (!mbss) { if ((supports_11d) && (is_11d != ifp->vif->is_11d)) { @@ -4708,6 +4616,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, WARN_ON(1); } + brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); brcmf_net_setcarrier(ifp, true); @@ -4764,6 +4673,8 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) brcmf_err("BRCMF_C_UP error %d\n", err); + + brcmf_vif_clear_mgmt_ies(ifp->vif); } else { bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx); bss_enable.enable = cpu_to_le32(0); @@ -5506,7 +5417,8 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, u32 reason = e->reason; struct station_info sinfo; - brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); + brcmf_dbg(CONN, "event %s (%u), reason %d\n", + brcmf_fweh_event_name(event), event, reason); if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS && ndev != cfg_to_ndev(cfg)) { brcmf_dbg(CONN, "AP mode link down\n"); @@ -6424,6 +6336,7 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 8889832c17e0..0c9a7081fca9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -271,7 +271,7 @@ struct brcmf_cfg80211_wowl { * @pub: common driver information. * @channel: current channel. * @active_scan: current scan mode. - * @sched_escan: e-scan for scheduled scan support running. + * @internal_escan: indicates internally initiated e-scan is running. * @ibss_starter: indicates this sta is ibss starter. * @pwr_save: indicate whether dongle to support power save mode. * @dongle_up: indicate whether dongle up or not. @@ -303,7 +303,7 @@ struct brcmf_cfg80211_info { struct brcmf_pub *pub; u32 channel; bool active_scan; - bool sched_escan; + bool internal_escan; bool ibss_starter; bool pwr_save; bool dongle_up; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 5eaac13e2317..9e6f60a0ec3e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -239,7 +239,13 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, if (eh->h_proto == htons(ETH_P_PAE)) atomic_inc(&ifp->pend_8021x_cnt); - ret = brcmf_fws_process_skb(ifp, skb); + /* determine the priority */ + if ((skb->priority == 0) || (skb->priority > 7)) + skb->priority = cfg80211_classify8021d(skb, NULL); + + ret = brcmf_proto_tx_queue_data(drvr, ifp->ifidx, skb); + if (ret < 0) + brcmf_txfinalize(ifp, skb, false); done: if (ret) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 79c081fd560f..c79306b57532 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -69,7 +69,7 @@ static struct brcmf_fweh_event_name fweh_event_names[] = { * * @code: code to lookup. */ -static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) { int i; for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) { @@ -79,7 +79,7 @@ static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) return "unknown"; } #else -static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) +const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code) { return "nodebug"; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 26ff5a9648f3..5fba4b49f3b3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -287,6 +287,8 @@ struct brcmf_fweh_info { void *data); }; +const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code); + void brcmf_fweh_attach(struct brcmf_pub *drvr); void brcmf_fweh_detach(struct brcmf_pub *drvr); int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index a4118c0ef6ca..9a1eb5ab6c4b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -131,6 +131,7 @@ #define BRCMF_TXBF_MU_BFR_CAP BIT(1) #define BRCMF_MAXPMKID 16 /* max # PMKID cache entries */ +#define BRCMF_NUMCHANNELS 64 #define BRCMF_PFN_MACADDR_CFG_VER 1 #define BRCMF_PFN_MAC_OUI_ONLY BIT(0) @@ -719,6 +720,21 @@ struct brcmf_pno_param_le { }; /** + * struct brcmf_pno_config_le - PNO channel configuration. + * + * @reporttype: determines what is reported. + * @channel_num: number of channels specified in @channel_list. + * @channel_list: channels to use in PNO scan. + * @flags: reserved. + */ +struct brcmf_pno_config_le { + __le32 reporttype; + __le32 channel_num; + __le16 channel_list[BRCMF_NUMCHANNELS]; + __le32 flags; +}; + +/** * struct brcmf_pno_net_param_le - scan parameters per preferred network. * * @ssid: ssid name and its length. @@ -769,6 +785,13 @@ struct brcmf_pno_scanresults_le { __le32 count; }; +struct brcmf_pno_scanresults_v2_le { + __le32 version; + __le32 status; + __le32 count; + __le32 scan_ch_bucket; +}; + /** * struct brcmf_pno_macaddr_le - to configure PNO macaddr randomization. * diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index a190f535efc9..5f1a5929cb30 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2100,16 +2100,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) int rc = 0; brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); - /* determine the priority */ - if ((skb->priority == 0) || (skb->priority > 7)) - skb->priority = cfg80211_classify8021d(skb, NULL); - - if (fws->avoid_queueing) { - rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb); - if (rc < 0) - brcmf_txfinalize(ifp, skb, false); - return rc; - } /* set control buffer information */ skcb->if_flags = 0; @@ -2442,6 +2432,11 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr) kfree(fws); } +bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws) +{ + return !fws->avoid_queueing; +} + bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) { if (!fws->creditmap_received) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index ef0ad8597c8a..96df66073b2a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -20,6 +20,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr); void brcmf_fws_deinit(struct brcmf_pub *drvr); +bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws); bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 2b9a2bc429d6..d2c834c3b2fc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -87,11 +87,6 @@ struct msgbuf_common_hdr { __le32 request_id; }; -struct msgbuf_buf_addr { - __le32 low_addr; - __le32 high_addr; -}; - struct msgbuf_ioctl_req_hdr { struct msgbuf_common_hdr msg; __le32 cmd; @@ -227,7 +222,10 @@ struct brcmf_msgbuf { struct brcmf_commonring **commonrings; struct brcmf_commonring **flowrings; dma_addr_t *flowring_dma_handle; - u16 nrof_flowrings; + + u16 max_flowrings; + u16 max_submissionrings; + u16 max_completionrings; u16 rx_dataoffset; u32 max_rxbufpost; @@ -610,7 +608,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, create->msg.request_id = 0; create->tid = brcmf_flowring_tid(msgbuf->flow, flowid); create->flow_ring_id = cpu_to_le16(flowid + - BRCMF_NROF_H2D_COMMON_MSGRINGS); + BRCMF_H2D_MSGRING_FLOWRING_IDSTART); memcpy(create->sa, work->sa, ETH_ALEN); memcpy(create->da, work->da, ETH_ALEN); address = (u64)msgbuf->flowring_dma_handle[flowid]; @@ -760,7 +758,7 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker) u32 flowid; msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work); - for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->nrof_flowrings) { + for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->max_flowrings) { clear_bit(flowid, msgbuf->flow_map); brcmf_msgbuf_txflow(msgbuf, flowid); } @@ -782,8 +780,8 @@ static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid, } -static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx, - u8 offset, struct sk_buff *skb) +static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *skb) { struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; struct brcmf_flowring *flow = msgbuf->flow; @@ -866,7 +864,7 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) tx_status = (struct msgbuf_tx_status *)buf; idx = le32_to_cpu(tx_status->msg.request_id); flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id); - flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, msgbuf->tx_pktids, idx); if (!skb) @@ -1174,7 +1172,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf, flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf; flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id); - flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; status = le16_to_cpu(flowring_create_resp->compl_hdr.status); if (status) { @@ -1202,7 +1200,7 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf, flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf; flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id); - flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; status = le16_to_cpu(flowring_delete_resp->compl_hdr.status); if (status) { @@ -1307,7 +1305,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) brcmf_msgbuf_process_rx(msgbuf, buf); for_each_set_bit(flowid, msgbuf->txstatus_done_map, - msgbuf->nrof_flowrings) { + msgbuf->max_flowrings) { clear_bit(flowid, msgbuf->txstatus_done_map); commonring = msgbuf->flowrings[flowid]; qlen = brcmf_flowring_qlen(msgbuf->flow, flowid); @@ -1349,7 +1347,7 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) delete->msg.request_id = 0; delete->flow_ring_id = cpu_to_le16(flowid + - BRCMF_NROF_H2D_COMMON_MSGRINGS); + BRCMF_H2D_MSGRING_FLOWRING_IDSTART); delete->reason = 0; brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n", @@ -1427,10 +1425,10 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) if_msgbuf = drvr->bus_if->msgbuf; - if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { + if (if_msgbuf->max_flowrings >= BRCMF_FLOWRING_HASHSIZE) { brcmf_err("driver not configured for this many flowrings %d\n", - if_msgbuf->nrof_flowrings); - if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; + if_msgbuf->max_flowrings); + if_msgbuf->max_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; } msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); @@ -1443,7 +1441,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) goto fail; } INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); - count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); + count = BITS_TO_LONGS(if_msgbuf->max_flowrings); count = count * sizeof(unsigned long); msgbuf->flow_map = kzalloc(count, GFP_KERNEL); if (!msgbuf->flow_map) @@ -1467,7 +1465,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) drvr->proto->hdrpull = brcmf_msgbuf_hdrpull; drvr->proto->query_dcmd = brcmf_msgbuf_query_dcmd; drvr->proto->set_dcmd = brcmf_msgbuf_set_dcmd; - drvr->proto->txdata = brcmf_msgbuf_txdata; + drvr->proto->tx_queue_data = brcmf_msgbuf_tx_queue_data; drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode; drvr->proto->delete_peer = brcmf_msgbuf_delete_peer; drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer; @@ -1479,8 +1477,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) msgbuf->commonrings = (struct brcmf_commonring **)if_msgbuf->commonrings; msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings; - msgbuf->nrof_flowrings = if_msgbuf->nrof_flowrings; - msgbuf->flowring_dma_handle = kzalloc(msgbuf->nrof_flowrings * + msgbuf->max_flowrings = if_msgbuf->max_flowrings; + msgbuf->flowring_dma_handle = kzalloc(msgbuf->max_flowrings * sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL); if (!msgbuf->flowring_dma_handle) goto fail; @@ -1501,7 +1499,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) goto fail; msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev, - if_msgbuf->nrof_flowrings); + if_msgbuf->max_flowrings); if (!msgbuf->flow) goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h index ee6906a3c3f6..f93ba6be1ef8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h @@ -31,6 +31,10 @@ #define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32 #define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48 +struct msgbuf_buf_addr { + __le32 low_addr; + __le32 high_addr; +}; int brcmf_proto_msgbuf_rx_trigger(struct device *dev); void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 3deba90c7eb5..048027f2085b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -135,7 +135,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_PCIE_MB_INT_D2H3_DB1) #define BRCMF_PCIE_MIN_SHARED_VERSION 5 -#define BRCMF_PCIE_MAX_SHARED_VERSION 5 +#define BRCMF_PCIE_MAX_SHARED_VERSION 6 #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF #define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000 #define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000 @@ -166,17 +166,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_RING_MEM_SZ 16 #define BRCMF_RING_STATE_SZ 8 -#define BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET 4 -#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8 -#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12 -#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16 -#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20 -#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28 -#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36 -#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44 -#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0 -#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52 - #define BRCMF_DEF_MAX_RXBUFPOST 255 #define BRCMF_CONSOLE_BUFADDR_OFFSET 8 @@ -231,7 +220,9 @@ struct brcmf_pcie_shared_info { struct brcmf_pcie_ringbuf *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; struct brcmf_pcie_ringbuf *flowrings; u16 max_rxbufpost; - u32 nrof_flowrings; + u16 max_flowrings; + u16 max_submissionrings; + u16 max_completionrings; u32 rx_dataoffset; u32 htod_mb_data_addr; u32 dtoh_mb_data_addr; @@ -241,6 +232,7 @@ struct brcmf_pcie_shared_info { dma_addr_t scratch_dmahandle; void *ringupd; dma_addr_t ringupd_dmahandle; + u8 version; }; struct brcmf_pcie_core_info { @@ -284,6 +276,36 @@ struct brcmf_pcie_ringbuf { u8 id; }; +/** + * struct brcmf_pcie_dhi_ringinfo - dongle/host interface shared ring info + * + * @ringmem: dongle memory pointer to ring memory location + * @h2d_w_idx_ptr: h2d ring write indices dongle memory pointers + * @h2d_r_idx_ptr: h2d ring read indices dongle memory pointers + * @d2h_w_idx_ptr: d2h ring write indices dongle memory pointers + * @d2h_r_idx_ptr: d2h ring read indices dongle memory pointers + * @h2d_w_idx_hostaddr: h2d ring write indices host memory pointers + * @h2d_r_idx_hostaddr: h2d ring read indices host memory pointers + * @d2h_w_idx_hostaddr: d2h ring write indices host memory pointers + * @d2h_r_idx_hostaddr: d2h ring reaD indices host memory pointers + * @max_flowrings: maximum number of tx flow rings supported. + * @max_submissionrings: maximum number of submission rings(h2d) supported. + * @max_completionrings: maximum number of completion rings(d2h) supported. + */ +struct brcmf_pcie_dhi_ringinfo { + __le32 ringmem; + __le32 h2d_w_idx_ptr; + __le32 h2d_r_idx_ptr; + __le32 d2h_w_idx_ptr; + __le32 d2h_r_idx_ptr; + struct msgbuf_buf_addr h2d_w_idx_hostaddr; + struct msgbuf_buf_addr h2d_r_idx_hostaddr; + struct msgbuf_buf_addr d2h_w_idx_hostaddr; + struct msgbuf_buf_addr d2h_r_idx_hostaddr; + __le16 max_flowrings; + __le16 max_submissionrings; + __le16 max_completionrings; +}; static const u32 brcmf_ring_max_item[BRCMF_NROF_COMMON_MSGRINGS] = { BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM, @@ -1054,26 +1076,35 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) { struct brcmf_pcie_ringbuf *ring; struct brcmf_pcie_ringbuf *rings; - u32 ring_addr; u32 d2h_w_idx_ptr; u32 d2h_r_idx_ptr; u32 h2d_w_idx_ptr; u32 h2d_r_idx_ptr; - u32 addr; u32 ring_mem_ptr; u32 i; u64 address; u32 bufsz; - u16 max_sub_queues; u8 idx_offset; - - ring_addr = devinfo->shared.ring_info_addr; - brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr); - addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES; - max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr); + struct brcmf_pcie_dhi_ringinfo ringinfo; + u16 max_flowrings; + u16 max_submissionrings; + u16 max_completionrings; + + memcpy_fromio(&ringinfo, devinfo->tcm + devinfo->shared.ring_info_addr, + sizeof(ringinfo)); + if (devinfo->shared.version >= 6) { + max_submissionrings = le16_to_cpu(ringinfo.max_submissionrings); + max_flowrings = le16_to_cpu(ringinfo.max_flowrings); + max_completionrings = le16_to_cpu(ringinfo.max_completionrings); + } else { + max_submissionrings = le16_to_cpu(ringinfo.max_flowrings); + max_flowrings = max_submissionrings - + BRCMF_NROF_H2D_COMMON_MSGRINGS; + max_completionrings = BRCMF_NROF_D2H_COMMON_MSGRINGS; + } if (devinfo->dma_idx_sz != 0) { - bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) * + bufsz = (max_submissionrings + max_completionrings) * devinfo->dma_idx_sz * 2; devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz, &devinfo->idxbuf_dmahandle, @@ -1083,14 +1114,10 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) } if (devinfo->dma_idx_sz == 0) { - addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET; - d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); - addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET; - d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); - addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET; - h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); - addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET; - h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + d2h_w_idx_ptr = le32_to_cpu(ringinfo.d2h_w_idx_ptr); + d2h_r_idx_ptr = le32_to_cpu(ringinfo.d2h_r_idx_ptr); + h2d_w_idx_ptr = le32_to_cpu(ringinfo.h2d_w_idx_ptr); + h2d_r_idx_ptr = le32_to_cpu(ringinfo.h2d_r_idx_ptr); idx_offset = sizeof(u32); devinfo->write_ptr = brcmf_pcie_write_tcm16; devinfo->read_ptr = brcmf_pcie_read_tcm16; @@ -1103,34 +1130,42 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) devinfo->read_ptr = brcmf_pcie_read_idx; h2d_w_idx_ptr = 0; - addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET; address = (u64)devinfo->idxbuf_dmahandle; - brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); - brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); - - h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset; - addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET; - address += max_sub_queues * idx_offset; - brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); - brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); - - d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset; - addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET; - address += max_sub_queues * idx_offset; - brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); - brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); + ringinfo.h2d_w_idx_hostaddr.low_addr = + cpu_to_le32(address & 0xffffffff); + ringinfo.h2d_w_idx_hostaddr.high_addr = + cpu_to_le32(address >> 32); + + h2d_r_idx_ptr = h2d_w_idx_ptr + + max_submissionrings * idx_offset; + address += max_submissionrings * idx_offset; + ringinfo.h2d_r_idx_hostaddr.low_addr = + cpu_to_le32(address & 0xffffffff); + ringinfo.h2d_r_idx_hostaddr.high_addr = + cpu_to_le32(address >> 32); + + d2h_w_idx_ptr = h2d_r_idx_ptr + + max_submissionrings * idx_offset; + address += max_submissionrings * idx_offset; + ringinfo.d2h_w_idx_hostaddr.low_addr = + cpu_to_le32(address & 0xffffffff); + ringinfo.d2h_w_idx_hostaddr.high_addr = + cpu_to_le32(address >> 32); d2h_r_idx_ptr = d2h_w_idx_ptr + - BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; - addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET; - address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; - brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); - brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); + max_completionrings * idx_offset; + address += max_completionrings * idx_offset; + ringinfo.d2h_r_idx_hostaddr.low_addr = + cpu_to_le32(address & 0xffffffff); + ringinfo.d2h_r_idx_hostaddr.high_addr = + cpu_to_le32(address >> 32); + + memcpy_toio(devinfo->tcm + devinfo->shared.ring_info_addr, + &ringinfo, sizeof(ringinfo)); brcmf_dbg(PCIE, "Using host memory indices\n"); } - addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET; - ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + ring_mem_ptr = le32_to_cpu(ringinfo.ringmem); for (i = 0; i < BRCMF_NROF_H2D_COMMON_MSGRINGS; i++) { ring = brcmf_pcie_alloc_dma_and_ring(devinfo, i, ring_mem_ptr); @@ -1161,20 +1196,19 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) ring_mem_ptr += BRCMF_RING_MEM_SZ; } - devinfo->shared.nrof_flowrings = - max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS; - rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring), - GFP_KERNEL); + devinfo->shared.max_flowrings = max_flowrings; + devinfo->shared.max_submissionrings = max_submissionrings; + devinfo->shared.max_completionrings = max_completionrings; + rings = kcalloc(max_flowrings, sizeof(*ring), GFP_KERNEL); if (!rings) goto fail; - brcmf_dbg(PCIE, "Nr of flowrings is %d\n", - devinfo->shared.nrof_flowrings); + brcmf_dbg(PCIE, "Nr of flowrings is %d\n", max_flowrings); - for (i = 0; i < devinfo->shared.nrof_flowrings; i++) { + for (i = 0; i < max_flowrings; i++) { ring = &rings[i]; ring->devinfo = devinfo; - ring->id = i + BRCMF_NROF_COMMON_MSGRINGS; + ring->id = i + BRCMF_H2D_MSGRING_FLOWRING_IDSTART; brcmf_commonring_register_cb(&ring->commonring, brcmf_pcie_ring_mb_ring_bell, brcmf_pcie_ring_mb_update_rptr, @@ -1357,17 +1391,16 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, { struct brcmf_pcie_shared_info *shared; u32 addr; - u32 version; shared = &devinfo->shared; shared->tcm_base_address = sharedram_addr; shared->flags = brcmf_pcie_read_tcm32(devinfo, sharedram_addr); - version = shared->flags & BRCMF_PCIE_SHARED_VERSION_MASK; - brcmf_dbg(PCIE, "PCIe protocol version %d\n", version); - if ((version > BRCMF_PCIE_MAX_SHARED_VERSION) || - (version < BRCMF_PCIE_MIN_SHARED_VERSION)) { - brcmf_err("Unsupported PCIE version %d\n", version); + shared->version = (u8)(shared->flags & BRCMF_PCIE_SHARED_VERSION_MASK); + brcmf_dbg(PCIE, "PCIe protocol version %d\n", shared->version); + if ((shared->version > BRCMF_PCIE_MAX_SHARED_VERSION) || + (shared->version < BRCMF_PCIE_MIN_SHARED_VERSION)) { + brcmf_err("Unsupported PCIE version %d\n", shared->version); return -EINVAL; } @@ -1661,18 +1694,18 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, bus->msgbuf->commonrings[i] = &devinfo->shared.commonrings[i]->commonring; - flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings), + flowrings = kcalloc(devinfo->shared.max_flowrings, sizeof(*flowrings), GFP_KERNEL); if (!flowrings) goto fail; - for (i = 0; i < devinfo->shared.nrof_flowrings; i++) + for (i = 0; i < devinfo->shared.max_flowrings; i++) flowrings[i] = &devinfo->shared.flowrings[i].commonring; bus->msgbuf->flowrings = flowrings; bus->msgbuf->rx_dataoffset = devinfo->shared.rx_dataoffset; bus->msgbuf->max_rxbufpost = devinfo->shared.max_rxbufpost; - bus->msgbuf->nrof_flowrings = devinfo->shared.nrof_flowrings; + bus->msgbuf->max_flowrings = devinfo->shared.max_flowrings; init_waitqueue_head(&devinfo->mbdata_resp_wait); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c new file mode 100644 index 000000000000..f273cab0da10 --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016 Broadcom + * + * 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. + */ +#include <linux/netdevice.h> +#include <net/cfg80211.h> + +#include "core.h" +#include "debug.h" +#include "fwil.h" +#include "fwil_types.h" +#include "cfg80211.h" +#include "pno.h" + +#define BRCMF_PNO_VERSION 2 +#define BRCMF_PNO_REPEAT 4 +#define BRCMF_PNO_FREQ_EXPO_MAX 3 +#define BRCMF_PNO_IMMEDIATE_SCAN_BIT 3 +#define BRCMF_PNO_ENABLE_BD_SCAN_BIT 5 +#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 +#define BRCMF_PNO_REPORT_SEPARATELY_BIT 11 +#define BRCMF_PNO_SCAN_INCOMPLETE 0 +#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF +#define BRCMF_PNO_HIDDEN_BIT 2 +#define BRCMF_PNO_SCHED_SCAN_PERIOD 30 + +static int brcmf_pno_channel_config(struct brcmf_if *ifp, + struct brcmf_pno_config_le *cfg) +{ + cfg->reporttype = 0; + cfg->flags = 0; + + return brcmf_fil_iovar_data_set(ifp, "pfn_cfg", cfg, sizeof(*cfg)); +} + +static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq, + u32 mscan, u32 bestn) +{ + struct brcmf_pno_param_le pfn_param; + u16 flags; + u32 pfnmem; + s32 err; + + memset(&pfn_param, 0, sizeof(pfn_param)); + pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); + + /* set extra pno params */ + flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) | + BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) | + BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = BRCMF_PNO_REPEAT; + pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; + + /* set up pno scan fr */ + if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { + brcmf_dbg(SCAN, "scan period too small, using minimum\n"); + scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; + } + pfn_param.scan_freq = cpu_to_le32(scan_freq); + + if (mscan) { + pfnmem = bestn; + + /* set bestn in firmware */ + err = brcmf_fil_iovar_int_set(ifp, "pfnmem", pfnmem); + if (err < 0) { + brcmf_err("failed to set pfnmem\n"); + goto exit; + } + /* get max mscan which the firmware supports */ + err = brcmf_fil_iovar_int_get(ifp, "pfnmem", &pfnmem); + if (err < 0) { + brcmf_err("failed to get pfnmem\n"); + goto exit; + } + mscan = min_t(u32, mscan, pfnmem); + pfn_param.mscan = mscan; + pfn_param.bestn = bestn; + flags |= BIT(BRCMF_PNO_ENABLE_BD_SCAN_BIT); + brcmf_dbg(INFO, "mscan=%d, bestn=%d\n", mscan, bestn); + } + + pfn_param.flags = cpu_to_le16(flags); + err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param, + sizeof(pfn_param)); + if (err) + brcmf_err("pfn_set failed, err=%d\n", err); + +exit: + return err; +} + +static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, + u8 *mac_mask) +{ + struct brcmf_pno_macaddr_le pfn_mac; + int err, i; + + pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; + pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; + + memcpy(pfn_mac.mac, mac_addr, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) { + pfn_mac.mac[i] &= mac_mask[i]; + pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]); + } + /* Clear multi bit */ + pfn_mac.mac[0] &= 0xFE; + /* Set locally administered */ + pfn_mac.mac[0] |= 0x02; + + err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, + sizeof(pfn_mac)); + if (err) + brcmf_err("pfn_macaddr failed, err=%d\n", err); + + return err; +} + +static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, + bool active) +{ + struct brcmf_pno_net_param_le pfn; + + pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); + pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); + pfn.wsec = cpu_to_le32(0); + pfn.infra = cpu_to_le32(1); + if (active) + pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); + pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len); + memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len); + return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); +} + +static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, + struct cfg80211_sched_scan_request *req) +{ + int i; + + if (!ssid || !req->ssids || !req->n_ssids) + return false; + + for (i = 0; i < req->n_ssids; i++) { + if (ssid->ssid_len == req->ssids[i].ssid_len) { + if (!strncmp(ssid->ssid, req->ssids[i].ssid, + ssid->ssid_len)) + return true; + } + } + return false; +} + +int brcmf_pno_clean(struct brcmf_if *ifp) +{ + int ret; + + /* Disable pfn */ + ret = brcmf_fil_iovar_int_set(ifp, "pfn", 0); + if (ret == 0) { + /* clear pfn */ + ret = brcmf_fil_iovar_data_set(ifp, "pfnclear", NULL, 0); + } + if (ret < 0) + brcmf_err("failed code %d\n", ret); + + return ret; +} + +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, + struct cfg80211_sched_scan_request *req) +{ + struct brcmu_d11inf *d11inf; + struct brcmf_pno_config_le pno_cfg; + struct cfg80211_ssid *ssid; + u16 chan; + int i, ret; + + /* clean up everything */ + ret = brcmf_pno_clean(ifp); + if (ret < 0) { + brcmf_err("failed error=%d\n", ret); + return ret; + } + + /* configure pno */ + ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0); + if (ret < 0) + return ret; + + /* configure random mac */ + if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + ret = brcmf_pno_set_random(ifp, req->mac_addr, + req->mac_addr_mask); + if (ret < 0) + return ret; + } + + /* configure channels to use */ + d11inf = &ifp->drvr->config->d11inf; + for (i = 0; i < req->n_channels; i++) { + chan = req->channels[i]->hw_value; + pno_cfg.channel_list[i] = cpu_to_le16(chan); + } + if (req->n_channels) { + pno_cfg.channel_num = cpu_to_le32(req->n_channels); + brcmf_pno_channel_config(ifp, &pno_cfg); + } + + /* configure each match set */ + for (i = 0; i < req->n_match_sets; i++) { + ssid = &req->match_sets[i].ssid; + if (!ssid->ssid_len) { + brcmf_err("skip broadcast ssid\n"); + continue; + } + + ret = brcmf_pno_add_ssid(ifp, ssid, + brcmf_is_ssid_active(ssid, req)); + if (ret < 0) + brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", + ret == 0 ? "set" : "failed", ssid->ssid); + } + /* Enable the PNO */ + ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1); + if (ret < 0) + brcmf_err("PNO enable failed!! ret=%d\n", ret); + + return ret; +} + diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h new file mode 100644 index 000000000000..bae55b2af78c --- /dev/null +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Broadcom + * + * 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 _BRCMF_PNO_H +#define _BRCMF_PNO_H + +#define BRCMF_PNO_SCAN_COMPLETE 1 +#define BRCMF_PNO_MAX_PFN_COUNT 16 +#define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10 +#define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508 + +/** + * brcmf_pno_clean - disable and clear pno in firmware. + * + * @ifp: interface object used. + */ +int brcmf_pno_clean(struct brcmf_if *ifp); + +/** + * brcmf_pno_start_sched_scan - initiate scheduled scan on device. + * + * @ifp: interface object used. + * @req: configuration parameters for scheduled scan. + */ +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, + struct cfg80211_sched_scan_request *req); + +#endif /* _BRCMF_PNO_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c index 26b68c367f57..d26ff219ef66 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c @@ -51,7 +51,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) drvr->bus_if->proto_type); goto fail; } - if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || + if (!proto->tx_queue_data || (proto->hdrpull == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->configure_addr_mode == NULL) || (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h index 57531f42190e..34b59feedeba 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h @@ -33,6 +33,8 @@ struct brcmf_proto { void *buf, uint len); int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len); + int (*tx_queue_data)(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *skb); int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *skb); void (*configure_addr_mode)(struct brcmf_pub *drvr, int ifidx, @@ -74,6 +76,13 @@ static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx, { return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len); } + +static inline int brcmf_proto_tx_queue_data(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *skb) +{ + return drvr->proto->tx_queue_data(drvr, ifidx, skb); +} + static inline int brcmf_proto_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *skb) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index b892dac70f4b..dfb0658713d9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -621,6 +621,7 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c index faf1ebe76068..b9672da24a9d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c @@ -179,7 +179,7 @@ s16 qm_norm32(s32 op) return u16extraSignBits; } -/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */ +/* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */ static const s16 log_table[] = { 0, 1455, @@ -212,7 +212,8 @@ static const s16 log_table[] = { 29717, 30498, 31267, - 32024 + 32024, + 32768 }; #define LOG_TABLE_SIZE 32 /* log_table size */ diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index d0407d9ad782..f1fb8a3c7a32 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -36,6 +36,7 @@ #define BRCM_CC_4330_CHIP_ID 0x4330 #define BRCM_CC_4334_CHIP_ID 0x4334 #define BRCM_CC_43340_CHIP_ID 43340 +#define BRCM_CC_43341_CHIP_ID 43341 #define BRCM_CC_43362_CHIP_ID 43362 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 |