static void brcms_ops_stop(struct ieee80211_hw *hw) { struct brcms_info *wl = hw->priv; int status; ieee80211_stop_queues(hw); if (wl->wlc == NULL) return; spin_lock_bh(&wl->lock); status = brcms_c_chipmatch(wl->wlc->hw->d11core); spin_unlock_bh(&wl->lock); if (!status) { brcms_err(wl->wlc->hw->d11core, "wl: brcms_ops_stop: chipmatch failed\n"); return; } bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, false); /* put driver in down state */ spin_lock_bh(&wl->lock); brcms_down(wl); spin_unlock_bh(&wl->lock); }
static int brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct brcms_info *wl = hw->priv; /* Just STA, AP and ADHOC for now */ if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC) { brcms_err(wl->wlc->hw->d11core, "%s: Attempt to add type %d, only STA, AP and AdHoc for now\n", __func__, vif->type); return -EOPNOTSUPP; } spin_lock_bh(&wl->lock); wl->mute_tx = false; brcms_c_mute(wl->wlc, false); if (vif->type == NL80211_IFTYPE_STATION) brcms_c_start_station(wl->wlc, vif->addr); else if (vif->type == NL80211_IFTYPE_AP) brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid, vif->bss_conf.ssid, vif->bss_conf.ssid_len); else if (vif->type == NL80211_IFTYPE_ADHOC) brcms_c_start_adhoc(wl->wlc, vif->addr); spin_unlock_bh(&wl->lock); return 0; }
/* * precondition: perimeter lock has been acquired */ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) { int i, entry; const u8 *pdata; struct firmware_hdr *hdr; for (i = 0; i < wl->fw.fw_cnt; i++) { hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; for (entry = 0; entry < wl->fw.hdr_num_entries[i]; entry++, hdr++) { u32 len = le32_to_cpu(hdr->len); if (le32_to_cpu(hdr->idx) == idx) { pdata = wl->fw.fw_bin[i]->data + le32_to_cpu(hdr->offset); *pbuf = kmemdup(pdata, len, GFP_ATOMIC); if (*pbuf == NULL) goto fail; return 0; } } } brcms_err(wl->wlc->hw->d11core, "ERROR: ucode buf tag:%d can not be found!\n", idx); *pbuf = NULL; fail: return -ENODATA; }
void brcms_fatal_error(struct brcms_info *wl) { brcms_err(wl->wlc->hw->d11core, "wl%d: fatal error, reinitializing\n", wl->wlc->pub->unit); brcms_reset(wl); ieee80211_restart_hw(wl->pub->ieee_hw); }
static int brcms_ops_start(struct ieee80211_hw *hw) { struct brcms_info *wl = hw->priv; bool blocked; int err; ieee80211_wake_queues(hw); spin_lock_bh(&wl->lock); blocked = brcms_rfkill_set_hw_state(wl); spin_unlock_bh(&wl->lock); if (!blocked) wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); spin_lock_bh(&wl->lock); /* avoid acknowledging frames before a non-monitor device is added */ wl->mute_tx = true; if (!wl->pub->up) if (!blocked) err = brcms_up(wl); else err = -ERFKILL; else err = -ENODEV; spin_unlock_bh(&wl->lock); if (err != 0) brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n", __func__, err); return err; }
static void brcms_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct brcms_info *wl = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); spin_lock_bh(&wl->lock); if (!wl->pub->up) { brcms_err(wl->wlc->hw->d11core, "ops->tx called while down\n"); kfree_skb(skb); goto done; } if (brcms_c_sendpkt_mac80211(wl->wlc, skb, hw)) tx_info->rate_driver_data[0] = control->sta; done: spin_unlock_bh(&wl->lock); }
static int brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct brcms_info *wl = hw->priv; /* Just STA for now */ if (vif->type != NL80211_IFTYPE_STATION) { brcms_err(wl->wlc->hw->d11core, "%s: Attempt to add type %d, only STA for now\n", __func__, vif->type); return -EOPNOTSUPP; } wl->mute_tx = false; brcms_c_mute(wl->wlc, false); return 0; }
static void brcms_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct brcms_info *wl = hw->priv; struct bcma_device *core = wl->wlc->hw->d11core; if (changed & BSS_CHANGED_ASSOC) { /* association status changed (associated/disassociated) * also implies a change in the AID. */ brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME, __func__, info->assoc ? "" : "dis"); spin_lock_bh(&wl->lock); brcms_c_associate_upd(wl->wlc, info->assoc); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_ERP_SLOT) { s8 val; /* slot timing changed */ if (info->use_short_slot) val = 1; else val = 0; spin_lock_bh(&wl->lock); brcms_c_set_shortslot_override(wl->wlc, val); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_HT) { /* 802.11n parameters changed */ u16 mode = info->ht_operation_mode; spin_lock_bh(&wl->lock); brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG, mode & IEEE80211_HT_OP_MODE_PROTECTION); brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF, mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS, mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BASIC_RATES) { struct ieee80211_supported_band *bi; u32 br_mask, i; u16 rate; struct brcm_rateset rs; int error; /* retrieve the current rates */ spin_lock_bh(&wl->lock); brcms_c_get_current_rateset(wl->wlc, &rs); spin_unlock_bh(&wl->lock); br_mask = info->basic_rates; bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)]; for (i = 0; i < bi->n_bitrates; i++) { /* convert to internal rate value */ rate = (bi->bitrates[i].bitrate << 1) / 10; /* set/clear basic rate flag */ brcms_set_basic_rate(&rs, rate, br_mask & 1); br_mask >>= 1; } /* update the rate set */ spin_lock_bh(&wl->lock); error = brcms_c_set_rateset(wl->wlc, &rs); spin_unlock_bh(&wl->lock); if (error) brcms_err(core, "changing basic rates failed: %d\n", error); } if (changed & BSS_CHANGED_BEACON_INT) { /* Beacon interval changed */ spin_lock_bh(&wl->lock); brcms_c_set_beacon_period(wl->wlc, info->beacon_int); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BSSID) { /* BSSID changed, for whatever reason (IBSS and managed mode) */ spin_lock_bh(&wl->lock); brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_SSID) { /* BSSID changed, for whatever reason (IBSS and managed mode) */ spin_lock_bh(&wl->lock); brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BEACON) { /* Beacon data changed, retrieve new beacon (beaconing modes) */ struct sk_buff *beacon; u16 tim_offset = 0; spin_lock_bh(&wl->lock); beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, info->dtim_period); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_AP_PROBE_RESP) { struct sk_buff *probe_resp; spin_lock_bh(&wl->lock); probe_resp = ieee80211_proberesp_get(hw, vif); brcms_c_set_new_probe_resp(wl->wlc, probe_resp); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BEACON_ENABLED) { /* Beaconing should be enabled/disabled (beaconing modes) */ brcms_err(core, "%s: Beacon enabled: %s\n", __func__, info->enable_beacon ? "true" : "false"); if (info->enable_beacon && hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) { brcms_c_enable_probe_resp(wl->wlc, true); } else { brcms_c_enable_probe_resp(wl->wlc, false); } } if (changed & BSS_CHANGED_CQM) { /* Connection quality monitor config changed */ brcms_err(core, "%s: cqm change: threshold %d, hys %d " " (implement)\n", __func__, info->cqm_rssi_thold, info->cqm_rssi_hyst); } if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ brcms_err(core, "%s: IBSS joined: %s (implement)\n", __func__, info->ibss_joined ? "true" : "false"); } if (changed & BSS_CHANGED_ARP_FILTER) { /* Hardware ARP filter address list or state changed */ brcms_err(core, "%s: arp filtering: %d addresses" " (implement)\n", __func__, info->arp_addr_cnt); } if (changed & BSS_CHANGED_QOS) { /* * QoS for this association was enabled/disabled. * Note that it is only ever disabled for station mode. */ brcms_err(core, "%s: qos enabled: %s (implement)\n", __func__, info->qos ? "true" : "false"); } return; }
/* * precondition: perimeter lock has been acquired */ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, bool state, int prio) { brcms_err(wl->wlc->hw->d11core, "Shouldn't be here %s\n", __func__); }
struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) { struct antsel_info *asi; struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); if (!asi) return NULL; asi->wlc = wlc; asi->pub = wlc->pub; asi->antsel_type = ANTSEL_NA; asi->antsel_avail = false; asi->antsel_antswitch = sprom->antswitch; if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) { switch (asi->antsel_antswitch) { case ANTSWITCH_TYPE_1: case ANTSWITCH_TYPE_2: case ANTSWITCH_TYPE_3: /* 4321/2 board with 2x3 switch logic */ asi->antsel_type = ANTSEL_2x3; /* Antenna selection availability */ if ((sprom->ant_available_bg == 7) || (sprom->ant_available_a == 7)) { asi->antsel_avail = true; } else if ( sprom->ant_available_bg == 3 || sprom->ant_available_a == 3) { asi->antsel_avail = false; } else { asi->antsel_avail = false; brcms_err(wlc->hw->d11core, "antsel_attach: 2o3 " "board cfg invalid\n"); } break; default: break; } } else if ((asi->pub->sromrev == 4) && (sprom->ant_available_bg == 7) && (sprom->ant_available_a == 0)) { /* hack to match old 4321CB2 cards with 2of3 antenna switch */ asi->antsel_type = ANTSEL_2x3; asi->antsel_avail = true; } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) { asi->antsel_type = ANTSEL_2x4; asi->antsel_avail = true; } /* Set the antenna selection type for the low driver */ brcms_b_antsel_type_set(wlc->hw, asi->antsel_type); /* Init (auto/manual) antenna selection */ brcms_c_antsel_init_cfg(asi, &asi->antcfg_11n, true); brcms_c_antsel_init_cfg(asi, &asi->antcfg_cur, true); return asi; }
static int brcms_ops_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { struct brcms_info *wl = hw->priv; struct scb *scb = &wl->wlc->pri_scb; int status; struct ieee80211_sta *sta = params->sta; enum ieee80211_ampdu_mlme_action action = params->action; u16 tid = params->tid; u8 buf_size = params->buf_size; if (WARN_ON(scb->magic != SCB_MAGIC)) return -EIDRM; switch (action) { case IEEE80211_AMPDU_RX_START: break; case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: spin_lock_bh(&wl->lock); status = brcms_c_aggregatable(wl->wlc, tid); spin_unlock_bh(&wl->lock); if (!status) { brcms_err(wl->wlc->hw->d11core, "START: tid %d is not agg\'able\n", tid); return -EINVAL; } ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: spin_lock_bh(&wl->lock); brcms_c_ampdu_flush(wl->wlc, sta, tid); spin_unlock_bh(&wl->lock); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: /* * BA window size from ADDBA response ('buf_size') defines how * many outstanding MPDUs are allowed for the BA stream by * recipient and traffic class. 'ampdu_factor' gives maximum * AMPDU size. */ spin_lock_bh(&wl->lock); brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size, (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor)) - 1); spin_unlock_bh(&wl->lock); /* Power save wakeup */ break; default: brcms_err(wl->wlc->hw->d11core, "%s: Invalid command, ignoring\n", __func__); } return 0; }