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;
}
示例#6
0
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;
}
示例#8
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;
}
示例#9
0
/*
 * 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__);
}
示例#10
0
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;
}
示例#11
0
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;
}