diff options
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211')
20 files changed, 352 insertions, 182 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index c7550dab6..f549c2560 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -166,41 +166,45 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler); sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler); sdio_release_host(sdiodev->func[1]); + sdiodev->sd_irq_requested = true; } return 0; } -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) { - struct brcmfmac_sdio_pd *pdata; - brcmf_dbg(SDIO, "Entering\n"); + brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n", + sdiodev->oob_irq_requested, + sdiodev->sd_irq_requested); - pdata = &sdiodev->settings->bus.sdio; - if (pdata->oob_irq_supported) { + if (sdiodev->oob_irq_requested) { + struct brcmfmac_sdio_pd *pdata; + + pdata = &sdiodev->settings->bus.sdio; 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); sdio_release_host(sdiodev->func[1]); - if (sdiodev->oob_irq_requested) { - sdiodev->oob_irq_requested = false; - if (sdiodev->irq_wake) { - disable_irq_wake(pdata->oob_irq_nr); - sdiodev->irq_wake = false; - } - free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); - sdiodev->irq_en = false; + sdiodev->oob_irq_requested = false; + if (sdiodev->irq_wake) { + disable_irq_wake(pdata->oob_irq_nr); + sdiodev->irq_wake = false; } - } else { + free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); + sdiodev->irq_en = false; + sdiodev->oob_irq_requested = false; + } + + if (sdiodev->sd_irq_requested) { sdio_claim_host(sdiodev->func[1]); sdio_release_irq(sdiodev->func[2]); sdio_release_irq(sdiodev->func[1]); sdio_release_host(sdiodev->func[1]); + sdiodev->sd_irq_requested = false; } - - return 0; } void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev, @@ -722,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, return -ENOMEM; err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, glom_skb); - if (err) + if (err) { + brcmu_pkt_buf_free_skb(glom_skb); goto done; + } skb_queue_walk(pktq, skb) { memcpy(skb->data, glom_skb->data, skb->len); @@ -1197,12 +1203,17 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); brcmf_dbg(SDIO, "Function: %d\n", func->num); - if (func->num != 1) - return; - bus_if = dev_get_drvdata(&func->dev); if (bus_if) { sdiodev = bus_if->bus_priv.sdio; + + /* start by unregistering irqs */ + brcmf_sdiod_intr_unregister(sdiodev); + + if (func->num != 1) + return; + + /* only proceed with rest of cleanup if func 1 */ brcmf_sdiod_remove(sdiodev); dev_set_drvdata(&sdiodev->func[1]->dev, NULL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 121baba7a..b8aec5e5e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -541,6 +541,21 @@ brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev) ADDR_INDIRECT); } +static int brcmf_get_first_free_bsscfgidx(struct brcmf_pub *drvr) +{ + int bsscfgidx; + + for (bsscfgidx = 0; bsscfgidx < BRCMF_MAX_IFS; bsscfgidx++) { + /* bsscfgidx 1 is reserved for legacy P2P */ + if (bsscfgidx == 1) + continue; + if (!drvr->iflist[bsscfgidx]) + return bsscfgidx; + } + + return -ENOMEM; +} + static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) { struct brcmf_mbss_ssid_le mbss_ssid_le; @@ -548,7 +563,7 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) int err; memset(&mbss_ssid_le, 0, sizeof(mbss_ssid_le)); - bsscfgidx = brcmf_get_next_free_bsscfgidx(ifp->drvr); + bsscfgidx = brcmf_get_first_free_bsscfgidx(ifp->drvr); if (bsscfgidx < 0) return bsscfgidx; @@ -586,7 +601,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, brcmf_dbg(INFO, "Adding vif \"%s\"\n", name); - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP, false); + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_AP); if (IS_ERR(vif)) return (struct wireless_dev *)vif; @@ -669,20 +684,24 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, return ERR_PTR(-EOPNOTSUPP); case NL80211_IFTYPE_AP: wdev = brcmf_ap_add_vif(wiphy, name, flags, params); - if (!IS_ERR(wdev)) - brcmf_cfg80211_update_proto_addr_mode(wdev); - return wdev; + break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params); - if (!IS_ERR(wdev)) - brcmf_cfg80211_update_proto_addr_mode(wdev); - return wdev; + break; case NL80211_IFTYPE_UNSPECIFIED: default: return ERR_PTR(-EINVAL); } + + if (IS_ERR(wdev)) + brcmf_err("add iface %s type %d failed: err=%d\n", + name, type, (int)PTR_ERR(wdev)); + else + brcmf_cfg80211_update_proto_addr_mode(wdev); + + return wdev; } static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc) @@ -756,9 +775,13 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, if (!aborted) cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); } else if (scan_request) { + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", aborted ? "Aborted" : "Done"); - cfg80211_scan_done(scan_request, aborted); + cfg80211_scan_done(scan_request, &info); } if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); @@ -766,12 +789,48 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, return err; } +static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; + struct brcmf_if *ifp = netdev_priv(ndev); + int ret; + int err; + + brcmf_cfg80211_arm_vif_event(cfg, ifp->vif); + + err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0); + if (err) { + brcmf_err("interface_remove failed %d\n", err); + goto err_unarm; + } + + /* wait for firmware event */ + ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL, + BRCMF_VIF_EVENT_TIMEOUT); + if (!ret) { + brcmf_err("timeout occurred\n"); + err = -EIO; + goto err_unarm; + } + + brcmf_remove_interface(ifp, true); + +err_unarm: + brcmf_cfg80211_arm_vif_event(cfg, NULL); + return err; +} + static int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct net_device *ndev = wdev->netdev; + if (ndev && ndev == cfg_to_ndev(cfg)) + return -ENOTSUPP; + /* vif event pending in firmware */ if (brcmf_cfg80211_vif_event_armed(cfg)) return -EBUSY; @@ -788,12 +847,13 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: return -EOPNOTSUPP; + case NL80211_IFTYPE_AP: + return brcmf_cfg80211_del_ap_iface(wiphy, wdev); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: @@ -2750,7 +2810,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, if (!bi->ctl_ch) { ch.chspec = le16_to_cpu(bi->chanspec); cfg->d11inf.decchspec(&ch); - bi->ctl_ch = ch.chnum; + bi->ctl_ch = ch.control_ch_num; } channel = bi->ctl_ch; @@ -2868,7 +2928,7 @@ static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, else band = wiphy->bands[NL80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(ch.chnum, band->band); + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); cfg->channel = freq; notify_channel = ieee80211_get_channel(wiphy, freq); @@ -2878,7 +2938,7 @@ static s32 brcmf_inform_ibss(struct brcmf_cfg80211_info *cfg, notify_ielen = le32_to_cpu(bi->ie_length); notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq); + brcmf_dbg(CONN, "channel: %d(%d)\n", ch.control_ch_num, freq); brcmf_dbg(CONN, "capability: %X\n", notify_capability); brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval); brcmf_dbg(CONN, "signal: %d\n", notify_signal); @@ -4439,7 +4499,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; - u16 chanspec; + u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); bool mbss; int is_11d; @@ -4515,16 +4575,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); + /* Parameters shared by all radio interfaces */ if (!mbss) { - chanspec = chandef_to_chanspec(&cfg->d11inf, - &settings->chandef); - err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); - if (err < 0) { - brcmf_err("Set Channel failed: chspec=%d, %d\n", - chanspec, err); - goto exit; - } - if (is_11d != ifp->vif->is_11d) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, is_11d); @@ -4572,6 +4624,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, err = -EINVAL; goto exit; } + + /* Interface specific setup */ if (dev_role == NL80211_IFTYPE_AP) { if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) brcmf_fil_iovar_int_set(ifp, "mbss", 1); @@ -4581,6 +4635,17 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("setting AP mode failed %d\n", err); goto exit; } + if (!mbss) { + /* Firmware 10.x requires setting channel after enabling + * AP and before bringing interface up. + */ + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + if (err < 0) { + brcmf_err("Set Channel failed: chspec=%d, %d\n", + chanspec, err); + goto exit; + } + } err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) { brcmf_err("BRCMF_C_UP error (%d)\n", err); @@ -4601,8 +4666,23 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("SET SSID error (%d)\n", err); goto exit; } + + if (settings->hidden_ssid) { + err = brcmf_fil_iovar_int_set(ifp, "closednet", 1); + if (err) { + brcmf_err("closednet error (%d)\n", err); + goto exit; + } + } + brcmf_dbg(TRACE, "AP mode configuration complete\n"); - } else { + } else if (dev_role == NL80211_IFTYPE_P2P_GO) { + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + if (err < 0) { + brcmf_err("Set Channel failed: chspec=%d, %d\n", + chanspec, err); + goto exit; + } err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, sizeof(ssid_le)); if (err < 0) { @@ -4619,7 +4699,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, } brcmf_dbg(TRACE, "GO mode configuration complete\n"); + } else { + WARN_ON(1); } + set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); brcmf_net_setcarrier(ifp, true); @@ -4650,6 +4733,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) return err; } + /* First BSS doesn't get a full reset */ + if (ifp->bsscfgidx == 0) + brcmf_fil_iovar_int_set(ifp, "closednet", 0); + memset(&join_params, 0, sizeof(join_params)); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, &join_params, sizeof(join_params)); @@ -4908,6 +4995,68 @@ exit: return err; } +static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = wdev->netdev; + struct brcmf_if *ifp; + struct brcmu_chan ch; + enum nl80211_band band = 0; + enum nl80211_chan_width width = 0; + u32 chanspec; + int freq, err; + + if (!ndev) + return -ENODEV; + ifp = netdev_priv(ndev); + + err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec); + if (err) { + brcmf_err("chanspec failed (%d)\n", err); + return err; + } + + ch.chspec = chanspec; + cfg->d11inf.decchspec(&ch); + + switch (ch.band) { + case BRCMU_CHAN_BAND_2G: + band = NL80211_BAND_2GHZ; + break; + case BRCMU_CHAN_BAND_5G: + band = NL80211_BAND_5GHZ; + break; + } + + switch (ch.bw) { + case BRCMU_CHAN_BW_80: + width = NL80211_CHAN_WIDTH_80; + break; + case BRCMU_CHAN_BW_40: + width = NL80211_CHAN_WIDTH_40; + break; + case BRCMU_CHAN_BW_20: + width = NL80211_CHAN_WIDTH_20; + break; + case BRCMU_CHAN_BW_80P80: + width = NL80211_CHAN_WIDTH_80P80; + break; + case BRCMU_CHAN_BW_160: + width = NL80211_CHAN_WIDTH_160; + break; + } + + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band); + chandef->chan = ieee80211_get_channel(wiphy, freq); + chandef->width = width; + chandef->center_freq1 = ieee80211_channel_to_frequency(ch.chnum, band); + chandef->center_freq2 = 0; + + return 0; +} + static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_crit_proto_id proto, @@ -5070,6 +5219,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .mgmt_tx = brcmf_cfg80211_mgmt_tx, .remain_on_channel = brcmf_p2p_remain_on_channel, .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, + .get_channel = brcmf_cfg80211_get_channel, .start_p2p_device = brcmf_p2p_start_device, .stop_p2p_device = brcmf_p2p_stop_device, .crit_proto_start = brcmf_cfg80211_crit_proto_start, @@ -5078,8 +5228,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { }; struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block) + enum nl80211_iftype type) { struct brcmf_cfg80211_vif *vif_walk; struct brcmf_cfg80211_vif *vif; @@ -5094,8 +5243,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, vif->wdev.wiphy = cfg->wiphy; vif->wdev.iftype = type; - vif->pm_block = pm_block; - brcmf_init_prof(&vif->profile); if (type == NL80211_IFTYPE_AP) { @@ -5296,7 +5443,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, else band = wiphy->bands[NL80211_BAND_5GHZ]; - freq = ieee80211_channel_to_frequency(ch.chnum, band->band); + freq = ieee80211_channel_to_frequency(ch.control_ch_num, band->band); notify_channel = ieee80211_get_channel(wiphy, freq); done: @@ -5352,7 +5499,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, const struct brcmf_event_msg *e, void *data) { - struct brcmf_if *ifp = netdev_priv(ndev); static int generation; u32 event = e->event_code; u32 reason = e->reason; @@ -5363,8 +5509,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, ndev != cfg_to_ndev(cfg)) { brcmf_dbg(CONN, "AP mode link down\n"); complete(&cfg->vif_disabled); - if (ifp->vif->mbss) - brcmf_remove_interface(ifp); return 0; } @@ -5491,7 +5635,7 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, ifevent->action, ifevent->flags, ifevent->ifidx, ifevent->bsscfgidx); - mutex_lock(&event->vif_event_lock); + spin_lock(&event->vif_event_lock); event->action = ifevent->action; vif = event->vif; @@ -5499,7 +5643,7 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, case BRCMF_E_IF_ADD: /* waiting process may have timed out */ if (!cfg->vif_event.vif) { - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); return -EBADF; } @@ -5510,24 +5654,24 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, ifp->ndev->ieee80211_ptr = &vif->wdev; SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy)); } - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); wake_up(&event->vif_wq); return 0; case BRCMF_E_IF_DEL: - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); /* event may not be upon user request */ if (brcmf_cfg80211_vif_event_armed(cfg)) wake_up(&event->vif_wq); return 0; case BRCMF_E_IF_CHANGE: - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); wake_up(&event->vif_wq); return 0; default: - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); break; } return -EINVAL; @@ -5648,7 +5792,7 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) static void init_vif_event(struct brcmf_cfg80211_vif_event *event) { init_waitqueue_head(&event->vif_wq); - mutex_init(&event->vif_event_lock); + spin_lock_init(&event->vif_event_lock); } static s32 brcmf_dongle_roam(struct brcmf_if *ifp) @@ -5818,14 +5962,15 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, channel = band->channels; index = band->n_channels; for (j = 0; j < band->n_channels; j++) { - if (channel[j].hw_value == ch.chnum) { + if (channel[j].hw_value == ch.control_ch_num) { index = j; break; } } channel[index].center_freq = - ieee80211_channel_to_frequency(ch.chnum, band->band); - channel[index].hw_value = ch.chnum; + ieee80211_channel_to_frequency(ch.control_ch_num, + band->band); + channel[index].hw_value = ch.control_ch_num; /* assuming the chanspecs order is HT20, * HT40 upper, HT40 lower, and VHT80. @@ -5927,7 +6072,7 @@ static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40)) continue; for (j = 0; j < band->n_channels; j++) { - if (band->channels[j].hw_value == ch.chnum) + if (band->channels[j].hw_value == ch.control_ch_num) break; } if (WARN_ON(j == band->n_channels)) @@ -6193,29 +6338,15 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (!combo) goto err; - c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); - if (!c0_limits) - goto err; - - if (p2p) { - p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); - if (!p2p_limits) - goto err; - } - - if (mbss) { - mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); - if (!mbss_limits) - goto err; - } - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); c = 0; i = 0; - combo[c].num_different_channels = 1; + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); + if (!c0_limits) + goto err; c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); if (p2p) { @@ -6233,6 +6364,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); } + combo[c].num_different_channels = 1; combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = c0_limits; @@ -6240,7 +6372,9 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (p2p) { c++; i = 0; - combo[c].num_different_channels = 1; + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); + if (!p2p_limits) + goto err; p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); p2p_limits[i].max = 1; @@ -6249,6 +6383,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); p2p_limits[i].max = 1; p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + combo[c].num_different_channels = 1; combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = p2p_limits; @@ -6256,14 +6391,19 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (mbss) { c++; + i = 0; + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); + if (!mbss_limits) + goto err; + mbss_limits[i].max = 4; + mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP); combo[c].beacon_int_infra_match = true; combo[c].num_different_channels = 1; - mbss_limits[0].max = 4; - mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); combo[c].max_interfaces = 4; - combo[c].n_limits = 1; + combo[c].n_limits = i; combo[c].limits = mbss_limits; } + wiphy->n_iface_combinations = n_combos; wiphy->iface_combinations = combo; return 0; @@ -6551,9 +6691,9 @@ static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, { u8 evt_action; - mutex_lock(&event->vif_event_lock); + spin_lock(&event->vif_event_lock); evt_action = event->action; - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); return evt_action == action; } @@ -6562,10 +6702,10 @@ void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, { struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; - mutex_lock(&event->vif_event_lock); + spin_lock(&event->vif_event_lock); event->vif = vif; event->action = 0; - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); } bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) @@ -6573,9 +6713,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; bool armed; - mutex_lock(&event->vif_event_lock); + spin_lock(&event->vif_event_lock); armed = event->vif != NULL; - mutex_unlock(&event->vif_event_lock); + spin_unlock(&event->vif_event_lock); return armed; } @@ -6715,11 +6855,10 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return NULL; } - ops = kzalloc(sizeof(*ops), GFP_KERNEL); + ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL); if (!ops) return NULL; - memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops)); ifp = netdev_priv(ndev); #ifdef CONFIG_PM if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) @@ -6740,7 +6879,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION); if (IS_ERR(vif)) goto wiphy_out; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 95e35bcc1..8889832c1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -20,6 +20,10 @@ /* for brcmu_d11inf */ #include <brcmu_d11.h> +#include "core.h" +#include "fwil_types.h" +#include "p2p.h" + #define WL_NUM_SCAN_MAX 10 #define WL_TLV_INFO_MAX 1024 #define WL_BSS_INFO_MAX 2048 @@ -167,7 +171,6 @@ struct vif_saved_ie { * @wdev: wireless device. * @profile: profile information. * @sme_state: SME state using enum brcmf_vif_status bits. - * @pm_block: power-management blocked. * @list: linked list. * @mgmt_rx_reg: registered rx mgmt frame types. * @mbss: Multiple BSS type, set if not first AP (not relevant for P2P). @@ -177,7 +180,6 @@ struct brcmf_cfg80211_vif { struct wireless_dev wdev; struct brcmf_cfg80211_profile profile; unsigned long sme_state; - bool pm_block; struct vif_saved_ie saved_ie; struct list_head list; u16 mgmt_rx_reg; @@ -225,7 +227,7 @@ struct escan_info { */ struct brcmf_cfg80211_vif_event { wait_queue_head_t vif_wq; - struct mutex vif_event_lock; + spinlock_t vif_event_lock; u8 action; struct brcmf_cfg80211_vif *vif; }; @@ -388,8 +390,7 @@ s32 brcmf_cfg80211_down(struct net_device *ndev); enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - enum nl80211_iftype type, - bool pm_block); + enum nl80211_iftype type); void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index d3fd6b1db..05f22ff81 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -685,6 +685,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_43602_CHIP_ID: case BRCM_CC_4371_CHIP_ID: return 0x180000; + case BRCM_CC_43465_CHIP_ID: + case BRCM_CC_43525_CHIP_ID: case BRCM_CC_4365_CHIP_ID: case BRCM_CC_4366_CHIP_ID: return 0x200000; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index b590499f6..65e8c8766 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -516,7 +516,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) /* set appropriate operations */ ndev->netdev_ops = &brcmf_netdev_ops_pri; - ndev->hard_header_len += drvr->hdrlen; + ndev->needed_headroom += drvr->hdrlen; ndev->ethtool_ops = &brcmf_ethtool_ops; drvr->rxsz = ndev->mtu + ndev->hard_header_len + @@ -548,12 +548,16 @@ fail: return -EBADE; } -static void brcmf_net_detach(struct net_device *ndev) +static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) { - if (ndev->reg_state == NETREG_REGISTERED) - unregister_netdev(ndev); - else + if (ndev->reg_state == NETREG_REGISTERED) { + if (rtnl_locked) + unregister_netdevice(ndev); + else + unregister_netdev(ndev); + } else { brcmf_cfg80211_free_netdev(ndev); + } } void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) @@ -634,7 +638,7 @@ fail: } struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, - bool is_p2pdev, char *name, u8 *mac_addr) + bool is_p2pdev, const char *name, u8 *mac_addr) { struct brcmf_if *ifp; struct net_device *ndev; @@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, brcmf_err("ERROR: netdev:%s already exists\n", ifp->ndev->name); netif_stop_queue(ifp->ndev); - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); drvr->iflist[bsscfgidx] = NULL; } else { brcmf_dbg(INFO, "netdev:%s ignore IF event\n", @@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, return ifp; } -static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx, + bool rtnl_locked) { struct brcmf_if *ifp; @@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->ndoffload_work); } - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, rtnl_locked); } else { /* Only p2p device interfaces which get dynamically created * end up here. In this case the p2p module should be informed @@ -738,43 +743,19 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) * serious troublesome side effects. The p2p module will clean * up the ifp if needed. */ - brcmf_p2p_ifp_removed(ifp); + brcmf_p2p_ifp_removed(ifp, rtnl_locked); kfree(ifp); } } -void brcmf_remove_interface(struct brcmf_if *ifp) +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked) { if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp)) return; brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx, ifp->ifidx); brcmf_fws_del_interface(ifp); - brcmf_del_if(ifp->drvr, ifp->bsscfgidx); -} - -int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) -{ - int ifidx; - int bsscfgidx; - bool available; - int highest; - - available = false; - bsscfgidx = 2; - highest = 2; - for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { - if (drvr->iflist[ifidx]) { - if (drvr->iflist[ifidx]->bsscfgidx == bsscfgidx) - bsscfgidx = highest + 1; - else if (drvr->iflist[ifidx]->bsscfgidx > highest) - highest = drvr->iflist[ifidx]->bsscfgidx; - } else { - available = true; - } - } - - return available ? bsscfgidx : -ENOMEM; + brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked); } #ifdef CONFIG_INET @@ -1081,9 +1062,9 @@ fail: brcmf_fws_deinit(drvr); } if (ifp) - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); if (p2p_ifp) - brcmf_net_detach(p2p_ifp->ndev); + brcmf_net_detach(p2p_ifp->ndev, false); drvr->iflist[0] = NULL; drvr->iflist[1] = NULL; if (drvr->settings->ignore_probe_fail) @@ -1152,7 +1133,7 @@ void brcmf_detach(struct device *dev) /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) - brcmf_remove_interface(drvr->iflist[i]); + brcmf_remove_interface(drvr->iflist[i], false); brcmf_cfg80211_detach(drvr->config); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 647d3cc2a..8fa34cad5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -215,9 +215,8 @@ char *brcmf_ifname(struct brcmf_if *ifp); struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, - bool is_p2pdev, char *name, u8 *mac_addr); -void brcmf_remove_interface(struct brcmf_if *ifp); -int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); + bool is_p2pdev, const char *name, u8 *mac_addr); +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index b39056125..79c081fd5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -18,6 +18,7 @@ #include "brcmu_wifi.h" #include "brcmu_utils.h" +#include "cfg80211.h" #include "core.h" #include "debug.h" #include "tracepoint.h" @@ -182,8 +183,13 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); - if (ifp && ifevent->action == BRCMF_E_IF_DEL) - brcmf_remove_interface(ifp); + if (ifp && ifevent->action == BRCMF_E_IF_DEL) { + bool armed = brcmf_cfg80211_vif_event_armed(drvr->config); + + /* Default handling in case no-one waits for this event */ + if (!armed) + brcmf_remove_interface(ifp, false); + } } /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 2ce319903..9f9024a7b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2101,7 +2101,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); /* determine the priority */ - if (!skb->priority) + if ((skb->priority == 0) || (skb->priority > 7)) skb->priority = cfg80211_classify8021d(skb, NULL); drvr->tx_multicast += !!multicast; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index a70cda6c0..de19c7c92 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1246,7 +1246,7 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, if (!bi->ctl_ch) { ch.chspec = le16_to_cpu(bi->chanspec); cfg->d11inf.decchspec(&ch); - bi->ctl_ch = ch.chnum; + bi->ctl_ch = ch.control_ch_num; } afx_hdl->peer_chan = bi->ctl_ch; brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", @@ -1385,7 +1385,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { - afx_hdl->peer_chan = ch.chnum; + afx_hdl->peer_chan = ch.control_ch_num; brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", afx_hdl->peer_chan); complete(&afx_hdl->act_frm_scan); @@ -1428,7 +1428,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, memcpy(&mgmt_frame->u, frame, mgmt_frame_len); mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); - freq = ieee80211_channel_to_frequency(ch.chnum, + freq = ieee80211_channel_to_frequency(ch.control_ch_num, ch.band == BRCMU_CHAN_BAND_2G ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ); @@ -1873,7 +1873,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) { - afx_hdl->peer_chan = ch.chnum; + afx_hdl->peer_chan = ch.control_ch_num; brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", afx_hdl->peer_chan); complete(&afx_hdl->act_frm_scan); @@ -1898,7 +1898,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, mgmt_frame = (u8 *)(rxframe + 1); mgmt_frame_len = e->datalen - sizeof(*rxframe); - freq = ieee80211_channel_to_frequency(ch.chnum, + freq = ieee80211_channel_to_frequency(ch.control_ch_num, ch.band == BRCMU_CHAN_BAND_2G ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ); @@ -2030,8 +2030,6 @@ static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p, err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request, sizeof(if_request)); - if (err) - return err; return err; } @@ -2076,8 +2074,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif) return ERR_PTR(-ENOSPC); - p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE, - false); + p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE); if (IS_ERR(p2p_vif)) { brcmf_err("could not create discovery vif\n"); return (struct wireless_dev *)p2p_vif; @@ -2177,7 +2174,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, return ERR_PTR(-EOPNOTSUPP); } - vif = brcmf_alloc_vif(cfg, type, false); + vif = brcmf_alloc_vif(cfg, type); if (IS_ERR(vif)) return (struct wireless_dev *)vif; brcmf_cfg80211_arm_vif_event(cfg, vif); @@ -2264,6 +2261,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) return 0; brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); + break; + default: return -ENOTSUPP; } @@ -2289,8 +2288,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) else err = 0; } - if (err) - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, true); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) @@ -2299,7 +2297,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) return err; } -void brcmf_p2p_ifp_removed(struct brcmf_if *ifp) +void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked) { struct brcmf_cfg80211_info *cfg; struct brcmf_cfg80211_vif *vif; @@ -2308,9 +2306,11 @@ void brcmf_p2p_ifp_removed(struct brcmf_if *ifp) vif = ifp->vif; cfg = wdev_to_cfg(&vif->wdev); cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - rtnl_lock(); + if (!rtnl_locked) + rtnl_lock(); cfg80211_unregister_wdev(&vif->wdev); - rtnl_unlock(); + if (!rtnl_locked) + rtnl_unlock(); brcmf_free_vif(vif); } @@ -2396,7 +2396,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) if (vif != NULL) { brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, false); } /* just set it all to zero */ memset(p2p, 0, sizeof(*p2p)); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h index a3bd18c23..8ce944753 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h @@ -155,7 +155,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, enum brcmf_fil_p2p_if_types if_type); -void brcmf_p2p_ifp_removed(struct brcmf_if *ifp); +void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked); int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); int brcmf_p2p_scan_prep(struct wiphy *wiphy, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 099879ce8..b3b2c27e7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -54,21 +54,25 @@ BRCMF_FW_NVRAM_DEF(43570, "/*(DEBLOBBED)*/", "brcmfmac43570-pcie.txt"); BRCMF_FW_NVRAM_DEF(4358, "/*(DEBLOBBED)*/", "brcmfmac4358-pcie.txt"); BRCMF_FW_NVRAM_DEF(4359, "/*(DEBLOBBED)*/", "brcmfmac4359-pcie.txt"); BRCMF_FW_NVRAM_DEF(4365B, "/*(DEBLOBBED)*/", "brcmfmac4365b-pcie.txt"); +BRCMF_FW_NVRAM_DEF(4365C, "/*(DEBLOBBED)*/", "brcmfmac4365c-pcie.txt"); BRCMF_FW_NVRAM_DEF(4366B, "/*(DEBLOBBED)*/", "brcmfmac4366b-pcie.txt"); BRCMF_FW_NVRAM_DEF(4366C, "/*(DEBLOBBED)*/", "brcmfmac4366c-pcie.txt"); BRCMF_FW_NVRAM_DEF(4371, "/*(DEBLOBBED)*/", "brcmfmac4371-pcie.txt"); static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), 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_4365_CHIP_ID, 0x0000000F, 4365B), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), 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/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index af4652047..88159a833 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1384,8 +1384,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, return -ENXIO; } if (rd->seq_num != rx_seq) { - brcmf_err("seq %d: sequence number error, expect %d\n", - rx_seq, rd->seq_num); + brcmf_dbg(SDIO, "seq %d, expected %d\n", rx_seq, rd->seq_num); bus->sdcnt.rx_badseq++; rd->seq_num = rx_seq; } @@ -3306,10 +3305,6 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } - /* Allow full data communication using DPC from now on. */ - brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); - bcmerror = 0; - err: brcmf_sdio_clkctl(bus, CLK_SDONLY, false); sdio_release_host(bus->sdiodev->func[1]); @@ -3666,7 +3661,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, str_shift = 11; break; default: - brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + brcmf_dbg(INFO, "No SDIO driver strength init needed for chip %s rev %d pmurev %d\n", ci->name, ci->chiprev, ci->pmurev); break; } @@ -4047,6 +4042,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev, } if (err == 0) { + /* Allow full data communication using DPC from now on. */ + brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); + err = brcmf_sdiod_intr_register(sdiodev); if (err != 0) brcmf_err("intr register failed:%d\n", err); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index dcf0ce8cd..f3da32fc6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -186,6 +186,7 @@ struct brcmf_sdio_dev { struct brcmf_bus *bus_if; struct brcmf_mp_device *settings; bool oob_irq_requested; + bool sd_irq_requested; bool irq_en; /* irq enable flags */ spinlock_t irq_en_lock; bool irq_wake; /* irq wake enable flags */ @@ -293,7 +294,7 @@ struct sdpcmd_regs { /* Register/deregister interrupt handler. */ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev); -int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); +void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); /* sdio device register access interface */ u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index 796f5f9d5..b7df576bb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -1079,8 +1079,10 @@ bool dma_rxfill(struct dma_pub *pub) pa = dma_map_single(di->dmadev, p->data, di->rxbufsize, DMA_FROM_DEVICE); - if (dma_mapping_error(di->dmadev, pa)) + if (dma_mapping_error(di->dmadev, pa)) { + brcmu_pkt_buf_free_skb(p); return false; + } /* save the free packet pointer */ di->rxp[rxout] = p; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index e16ee6063..c2a938b59 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -3349,8 +3349,8 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc) dma_rxfill(wlc_hw->di[RX_FIFO]); } -void -static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) { +static void brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) +{ u32 macintmask; bool fastclk; struct brcms_c_info *wlc = wlc_hw->wlc; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 99dac9b8a..b3aab2fe9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -27017,7 +27017,7 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core, tx_core = 1 - rx_core; num_samps = 1024; - desired_log2_pwr = (cal_type == 0) ? 13 : 13; + desired_log2_pwr = 13; wlc_phy_rx_iq_coeffs_nphy(pi, 0, &save_comp); zero_comp.a0 = zero_comp.b0 = zero_comp.a1 = zero_comp.b1 = 0x0; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c index dd9162722..0ab865de1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.c @@ -87,7 +87,7 @@ void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel, u16 chanspec) { - struct tx_power power; + struct tx_power power = { }; u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; /* Clear previous settings */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c index 2b2522bdd..d8b79cb72 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c @@ -107,6 +107,7 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch) u16 val; ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); + ch->control_ch_num = ch->chnum; switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) { case BRCMU_CHSPEC_D11N_BW_20: @@ -118,10 +119,10 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch) val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK; if (val == BRCMU_CHSPEC_D11N_SB_L) { ch->sb = BRCMU_CHAN_SB_L; - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; } else { ch->sb = BRCMU_CHAN_SB_U; - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; } break; default: @@ -147,6 +148,7 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) u16 val; ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK); + ch->control_ch_num = ch->chnum; switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) { case BRCMU_CHSPEC_D11AC_BW_20: @@ -158,10 +160,10 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK; if (val == BRCMU_CHSPEC_D11AC_SB_L) { ch->sb = BRCMU_CHAN_SB_L; - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; } else if (val == BRCMU_CHSPEC_D11AC_SB_U) { ch->sb = BRCMU_CHAN_SB_U; - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; } else { WARN_ON_ONCE(1); } @@ -172,16 +174,16 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch) BRCMU_CHSPEC_D11AC_SB_SHIFT); switch (ch->sb) { case BRCMU_CHAN_SB_LL: - ch->chnum -= CH_30MHZ_APART; + ch->control_ch_num -= CH_30MHZ_APART; break; case BRCMU_CHAN_SB_LU: - ch->chnum -= CH_10MHZ_APART; + ch->control_ch_num -= CH_10MHZ_APART; break; case BRCMU_CHAN_SB_UL: - ch->chnum += CH_10MHZ_APART; + ch->control_ch_num += CH_10MHZ_APART; break; case BRCMU_CHAN_SB_UU: - ch->chnum += CH_30MHZ_APART; + ch->control_ch_num += CH_30MHZ_APART; break; default: WARN_ON_ONCE(1); 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 699f2c278..3cc42bef6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -40,7 +40,9 @@ #define BRCM_CC_4339_CHIP_ID 0x4339 #define BRCM_CC_43430_CHIP_ID 43430 #define BRCM_CC_4345_CHIP_ID 0x4345 +#define BRCM_CC_43465_CHIP_ID 43465 #define BRCM_CC_4350_CHIP_ID 0x4350 +#define BRCM_CC_43525_CHIP_ID 43525 #define BRCM_CC_4354_CHIP_ID 0x4354 #define BRCM_CC_4356_CHIP_ID 0x4356 #define BRCM_CC_43566_CHIP_ID 43566 diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h index f9745ea8b..8b8b2ecb3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_d11.h @@ -125,14 +125,36 @@ enum brcmu_chan_sb { BRCMU_CHAN_SB_UU = BRCMU_CHAN_SB_LUU, }; +/** + * struct brcmu_chan - stores channel formats + * + * This structure can be used with functions translating chanspec into generic + * channel info and the other way. + * + * @chspec: firmware specific format + * @chnum: center channel number + * @control_ch_num: control channel number + * @band: frequency band + * @bw: channel width + * @sb: control sideband (location of control channel against the center one) + */ struct brcmu_chan { u16 chspec; u8 chnum; + u8 control_ch_num; u8 band; enum brcmu_chan_bw bw; enum brcmu_chan_sb sb; }; +/** + * struct brcmu_d11inf - provides functions translating channel format + * + * @io_type: determines version of channel format used by firmware + * @encchspec: encodes channel info into a chanspec, requires center channel + * number, ignores control one + * @decchspec: decodes chanspec into generic info + */ struct brcmu_d11inf { u8 io_type; |