Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/mac80211_if.c
178665 views
/*1* Copyright (c) 2010 Broadcom Corporation2* Copyright (c) 2013 Hauke Mehrtens <[email protected]>3*4* Permission to use, copy, modify, and/or distribute this software for any5* purpose with or without fee is hereby granted, provided that the above6* copyright notice and this permission notice appear in all copies.7*8* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY11* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION13* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN14* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15*/1617#define __UNDEF_NO_VERSION__18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt1920#include <linux/etherdevice.h>21#include <linux/sched.h>22#include <linux/firmware.h>23#include <linux/interrupt.h>24#include <linux/module.h>25#include <linux/bcma/bcma.h>26#include <linux/string_choices.h>27#include <net/mac80211.h>28#include <defs.h>29#include "phy/phy_int.h"30#include "d11.h"31#include "channel.h"32#include "scb.h"33#include "pub.h"34#include "ucode_loader.h"35#include "mac80211_if.h"36#include "main.h"37#include "debug.h"38#include "led.h"3940#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */41#define BRCMS_FLUSH_TIMEOUT 500 /* msec */4243/* Flags we support */44#define MAC_FILTERS (FIF_ALLMULTI | \45FIF_FCSFAIL | \46FIF_CONTROL | \47FIF_OTHER_BSS | \48FIF_BCN_PRBRESP_PROMISC | \49FIF_PSPOLL)5051#define CHAN2GHZ(channel, frequency, chflags) { \52.band = NL80211_BAND_2GHZ, \53.center_freq = (frequency), \54.hw_value = (channel), \55.flags = chflags, \56.max_antenna_gain = 0, \57.max_power = 19, \58}5960#define CHAN5GHZ(channel, chflags) { \61.band = NL80211_BAND_5GHZ, \62.center_freq = 5000 + 5*(channel), \63.hw_value = (channel), \64.flags = chflags, \65.max_antenna_gain = 0, \66.max_power = 21, \67}6869#define RATE(rate100m, _flags) { \70.bitrate = (rate100m), \71.flags = (_flags), \72.hw_value = (rate100m / 5), \73}7475struct firmware_hdr {76__le32 offset;77__le32 len;78__le32 idx;79};8081static const char * const brcms_firmwares[MAX_FW_IMAGES] = {82"brcm/bcm43xx",83NULL84};8586static int n_adapters_found;8788MODULE_AUTHOR("Broadcom Corporation");89MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");90MODULE_LICENSE("Dual BSD/GPL");91/* This needs to be adjusted when brcms_firmwares changes */92MODULE_FIRMWARE("brcm/bcm43xx-0.fw");93MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw");9495/* recognized BCMA Core IDs */96static struct bcma_device_id brcms_coreid_table[] = {97BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),98BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),99BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),100{},101};102MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);103104#if defined(CONFIG_BRCMDBG)105/*106* Module parameter for setting the debug message level. Available107* flags are specified by the BRCM_DL_* macros in108* drivers/net/wireless/brcm80211/include/defs.h.109*/110module_param_named(debug, brcm_msg_level, uint, 0644);111#endif112113static struct ieee80211_channel brcms_2ghz_chantable[] = {114CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),115CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),116CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),117CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),118CHAN2GHZ(5, 2432, 0),119CHAN2GHZ(6, 2437, 0),120CHAN2GHZ(7, 2442, 0),121CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),122CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),123CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),124CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),125CHAN2GHZ(12, 2467,126IEEE80211_CHAN_NO_IR |127IEEE80211_CHAN_NO_HT40PLUS),128CHAN2GHZ(13, 2472,129IEEE80211_CHAN_NO_IR |130IEEE80211_CHAN_NO_HT40PLUS),131CHAN2GHZ(14, 2484,132IEEE80211_CHAN_NO_IR |133IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |134IEEE80211_CHAN_NO_OFDM)135};136137static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {138/* UNII-1 */139CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),140CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),141CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),142CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),143/* UNII-2 */144CHAN5GHZ(52,145IEEE80211_CHAN_RADAR |146IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),147CHAN5GHZ(56,148IEEE80211_CHAN_RADAR |149IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),150CHAN5GHZ(60,151IEEE80211_CHAN_RADAR |152IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),153CHAN5GHZ(64,154IEEE80211_CHAN_RADAR |155IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),156/* MID */157CHAN5GHZ(100,158IEEE80211_CHAN_RADAR |159IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),160CHAN5GHZ(104,161IEEE80211_CHAN_RADAR |162IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),163CHAN5GHZ(108,164IEEE80211_CHAN_RADAR |165IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),166CHAN5GHZ(112,167IEEE80211_CHAN_RADAR |168IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),169CHAN5GHZ(116,170IEEE80211_CHAN_RADAR |171IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),172CHAN5GHZ(120,173IEEE80211_CHAN_RADAR |174IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),175CHAN5GHZ(124,176IEEE80211_CHAN_RADAR |177IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),178CHAN5GHZ(128,179IEEE80211_CHAN_RADAR |180IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),181CHAN5GHZ(132,182IEEE80211_CHAN_RADAR |183IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),184CHAN5GHZ(136,185IEEE80211_CHAN_RADAR |186IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),187CHAN5GHZ(140,188IEEE80211_CHAN_RADAR |189IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |190IEEE80211_CHAN_NO_HT40MINUS),191/* UNII-3 */192CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),193CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),194CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),195CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),196CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)197};198199/*200* The rate table is used for both 2.4G and 5G rates. The201* latter being a subset as it does not support CCK rates.202*/203static struct ieee80211_rate legacy_ratetable[] = {204RATE(10, 0),205RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),206RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),207RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),208RATE(60, 0),209RATE(90, 0),210RATE(120, 0),211RATE(180, 0),212RATE(240, 0),213RATE(360, 0),214RATE(480, 0),215RATE(540, 0),216};217218static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {219.band = NL80211_BAND_2GHZ,220.channels = brcms_2ghz_chantable,221.n_channels = ARRAY_SIZE(brcms_2ghz_chantable),222.bitrates = legacy_ratetable,223.n_bitrates = ARRAY_SIZE(legacy_ratetable),224.ht_cap = {225/* from include/linux/ieee80211.h */226.cap = IEEE80211_HT_CAP_GRN_FLD |227IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40,228.ht_supported = true,229.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,230.ampdu_density = AMPDU_DEF_MPDU_DENSITY,231.mcs = {232/* placeholders for now */233.rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},234.rx_highest = cpu_to_le16(500),235.tx_params = IEEE80211_HT_MCS_TX_DEFINED}236}237};238239static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {240.band = NL80211_BAND_5GHZ,241.channels = brcms_5ghz_nphy_chantable,242.n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),243.bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET,244.n_bitrates = ARRAY_SIZE(legacy_ratetable) -245BRCMS_LEGACY_5G_RATE_OFFSET,246.ht_cap = {247.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |248IEEE80211_HT_CAP_SGI_40,249.ht_supported = true,250.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,251.ampdu_density = AMPDU_DEF_MPDU_DENSITY,252.mcs = {253/* placeholders for now */254.rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},255.rx_highest = cpu_to_le16(500),256.tx_params = IEEE80211_HT_MCS_TX_DEFINED}257}258};259260/* flags the given rate in rateset as requested */261static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)262{263u32 i;264265for (i = 0; i < rs->count; i++) {266if (rate != (rs->rates[i] & 0x7f))267continue;268269if (is_br)270rs->rates[i] |= BRCMS_RATE_FLAG;271else272rs->rates[i] &= BRCMS_RATE_MASK;273return;274}275}276277/*278* This function frees the WL per-device resources.279*280* This function frees resources owned by the WL device pointed to281* by the wl parameter.282*283* precondition: can both be called locked and unlocked284*/285static void brcms_free(struct brcms_info *wl)286{287struct brcms_timer *t, *next;288289/* free ucode data */290if (wl->fw.fw_cnt)291brcms_ucode_data_free(&wl->ucode);292if (wl->irq)293free_irq(wl->irq, wl);294295/* kill dpc */296tasklet_kill(&wl->tasklet);297298if (wl->pub) {299brcms_debugfs_detach(wl->pub);300brcms_c_module_unregister(wl->pub, "linux", wl);301}302303/* free common resources */304if (wl->wlc) {305brcms_c_detach(wl->wlc);306wl->wlc = NULL;307wl->pub = NULL;308}309310/* virtual interface deletion is deferred so we cannot spinwait */311312/* wait for all pending callbacks to complete */313while (atomic_read(&wl->callbacks) > 0)314schedule();315316/* free timers */317for (t = wl->timers; t; t = next) {318next = t->next;319#ifdef DEBUG320kfree(t->name);321#endif322kfree(t);323}324}325326/*327* called from both kernel as from this kernel module (error flow on attach)328* precondition: perimeter lock is not acquired.329*/330static void brcms_remove(struct bcma_device *pdev)331{332struct ieee80211_hw *hw = bcma_get_drvdata(pdev);333struct brcms_info *wl = hw->priv;334335if (wl->wlc) {336brcms_led_unregister(wl);337wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);338wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);339ieee80211_unregister_hw(hw);340}341342brcms_free(wl);343344bcma_set_drvdata(pdev, NULL);345ieee80211_free_hw(hw);346}347348/*349* Precondition: Since this function is called in brcms_pci_probe() context,350* no locking is required.351*/352static void brcms_release_fw(struct brcms_info *wl)353{354int i;355for (i = 0; i < MAX_FW_IMAGES; i++) {356release_firmware(wl->fw.fw_bin[i]);357release_firmware(wl->fw.fw_hdr[i]);358}359}360361/*362* Precondition: Since this function is called in brcms_pci_probe() context,363* no locking is required.364*/365static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)366{367int status;368struct device *device = &pdev->dev;369char fw_name[100];370int i;371372memset(&wl->fw, 0, sizeof(struct brcms_firmware));373for (i = 0; i < MAX_FW_IMAGES; i++) {374if (brcms_firmwares[i] == NULL)375break;376sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],377UCODE_LOADER_API_VER);378status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);379if (status) {380wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",381KBUILD_MODNAME, fw_name);382return status;383}384sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],385UCODE_LOADER_API_VER);386status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);387if (status) {388wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",389KBUILD_MODNAME, fw_name);390return status;391}392wl->fw.hdr_num_entries[i] =393wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));394}395wl->fw.fw_cnt = i;396status = brcms_ucode_data_init(wl, &wl->ucode);397brcms_release_fw(wl);398return status;399}400401static void brcms_ops_tx(struct ieee80211_hw *hw,402struct ieee80211_tx_control *control,403struct sk_buff *skb)404{405struct brcms_info *wl = hw->priv;406struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);407408spin_lock_bh(&wl->lock);409if (!wl->pub->up) {410brcms_err(wl->wlc->hw->d11core, "ops->tx called while down\n");411kfree_skb(skb);412goto done;413}414if (brcms_c_sendpkt_mac80211(wl->wlc, skb, hw))415tx_info->rate_driver_data[0] = control->sta;416done:417spin_unlock_bh(&wl->lock);418}419420static int brcms_ops_start(struct ieee80211_hw *hw)421{422struct brcms_info *wl = hw->priv;423bool blocked;424int err;425426if (!wl->ucode.bcm43xx_bomminor) {427err = brcms_request_fw(wl, wl->wlc->hw->d11core);428if (err)429return -ENOENT;430}431432ieee80211_wake_queues(hw);433spin_lock_bh(&wl->lock);434blocked = brcms_rfkill_set_hw_state(wl);435spin_unlock_bh(&wl->lock);436if (!blocked)437wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);438439spin_lock_bh(&wl->lock);440/* avoid acknowledging frames before a non-monitor device is added */441wl->mute_tx = true;442443if (!wl->pub->up)444if (!blocked)445err = brcms_up(wl);446else447err = -ERFKILL;448else449err = -ENODEV;450spin_unlock_bh(&wl->lock);451452if (err != 0)453brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",454__func__, err);455456bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, true);457return err;458}459460static void brcms_ops_stop(struct ieee80211_hw *hw, bool suspend)461{462struct brcms_info *wl = hw->priv;463int status;464465ieee80211_stop_queues(hw);466467if (wl->wlc == NULL)468return;469470spin_lock_bh(&wl->lock);471status = brcms_c_chipmatch(wl->wlc->hw->d11core);472spin_unlock_bh(&wl->lock);473if (!status) {474brcms_err(wl->wlc->hw->d11core,475"wl: brcms_ops_stop: chipmatch failed\n");476return;477}478479bcma_core_pci_power_save(wl->wlc->hw->d11core->bus, false);480481/* put driver in down state */482spin_lock_bh(&wl->lock);483brcms_down(wl);484spin_unlock_bh(&wl->lock);485}486487static int488brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)489{490struct brcms_info *wl = hw->priv;491492/* Just STA, AP and ADHOC for now */493if (vif->type != NL80211_IFTYPE_STATION &&494vif->type != NL80211_IFTYPE_AP &&495vif->type != NL80211_IFTYPE_ADHOC) {496brcms_err(wl->wlc->hw->d11core,497"%s: Attempt to add type %d, only STA, AP and AdHoc for now\n",498__func__, vif->type);499return -EOPNOTSUPP;500}501502spin_lock_bh(&wl->lock);503wl->wlc->vif = vif;504wl->mute_tx = false;505brcms_c_mute(wl->wlc, false);506if (vif->type == NL80211_IFTYPE_STATION)507brcms_c_start_station(wl->wlc, vif->addr);508else if (vif->type == NL80211_IFTYPE_AP)509brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid,510vif->cfg.ssid, vif->cfg.ssid_len);511else if (vif->type == NL80211_IFTYPE_ADHOC)512brcms_c_start_adhoc(wl->wlc, vif->addr);513spin_unlock_bh(&wl->lock);514515return 0;516}517518static void519brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)520{521struct brcms_info *wl = hw->priv;522523spin_lock_bh(&wl->lock);524wl->wlc->vif = NULL;525spin_unlock_bh(&wl->lock);526}527528static int brcms_ops_config(struct ieee80211_hw *hw, int radio_idx,529u32 changed)530{531struct ieee80211_conf *conf = &hw->conf;532struct brcms_info *wl = hw->priv;533struct bcma_device *core = wl->wlc->hw->d11core;534int err = 0;535int new_int;536537spin_lock_bh(&wl->lock);538if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {539brcms_c_set_beacon_listen_interval(wl->wlc,540conf->listen_interval);541}542if (changed & IEEE80211_CONF_CHANGE_MONITOR)543brcms_dbg_info(core, "%s: change monitor mode: %s\n", __func__,544str_true_false(conf->flags &545IEEE80211_CONF_MONITOR));546if (changed & IEEE80211_CONF_CHANGE_PS)547brcms_err(core, "%s: change power-save mode: %s (implement)\n",548__func__,549str_true_false(conf->flags & IEEE80211_CONF_PS));550551if (changed & IEEE80211_CONF_CHANGE_POWER) {552err = brcms_c_set_tx_power(wl->wlc, conf->power_level);553if (err < 0) {554brcms_err(core, "%s: Error setting power_level\n",555__func__);556goto config_out;557}558new_int = brcms_c_get_tx_power(wl->wlc);559if (new_int != conf->power_level)560brcms_err(core,561"%s: Power level req != actual, %d %d\n",562__func__, conf->power_level,563new_int);564}565if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {566if (conf->chandef.width == NL80211_CHAN_WIDTH_20 ||567conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)568err = brcms_c_set_channel(wl->wlc,569conf->chandef.chan->hw_value);570else571err = -ENOTSUPP;572}573if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)574err = brcms_c_set_rate_limit(wl->wlc,575conf->short_frame_max_tx_count,576conf->long_frame_max_tx_count);577578config_out:579spin_unlock_bh(&wl->lock);580return err;581}582583static void584brcms_ops_bss_info_changed(struct ieee80211_hw *hw,585struct ieee80211_vif *vif,586struct ieee80211_bss_conf *info, u64 changed)587{588struct brcms_info *wl = hw->priv;589struct bcma_device *core = wl->wlc->hw->d11core;590591if (changed & BSS_CHANGED_ASSOC) {592/* association status changed (associated/disassociated)593* also implies a change in the AID.594*/595brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME,596__func__, vif->cfg.assoc ? "" : "dis");597spin_lock_bh(&wl->lock);598brcms_c_associate_upd(wl->wlc, vif->cfg.assoc);599spin_unlock_bh(&wl->lock);600}601if (changed & BSS_CHANGED_ERP_SLOT) {602s8 val;603604/* slot timing changed */605if (info->use_short_slot)606val = 1;607else608val = 0;609spin_lock_bh(&wl->lock);610brcms_c_set_shortslot_override(wl->wlc, val);611spin_unlock_bh(&wl->lock);612}613614if (changed & BSS_CHANGED_HT) {615/* 802.11n parameters changed */616u16 mode = info->ht_operation_mode;617618spin_lock_bh(&wl->lock);619brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG,620mode & IEEE80211_HT_OP_MODE_PROTECTION);621brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF,622mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);623brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS,624mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT);625spin_unlock_bh(&wl->lock);626}627if (changed & BSS_CHANGED_BASIC_RATES) {628struct ieee80211_supported_band *bi;629u32 br_mask, i;630u16 rate;631struct brcm_rateset rs;632int error;633634/* retrieve the current rates */635spin_lock_bh(&wl->lock);636brcms_c_get_current_rateset(wl->wlc, &rs);637spin_unlock_bh(&wl->lock);638639br_mask = info->basic_rates;640bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)];641for (i = 0; i < bi->n_bitrates; i++) {642/* convert to internal rate value */643rate = (bi->bitrates[i].bitrate << 1) / 10;644645/* set/clear basic rate flag */646brcms_set_basic_rate(&rs, rate, br_mask & 1);647br_mask >>= 1;648}649650/* update the rate set */651spin_lock_bh(&wl->lock);652error = brcms_c_set_rateset(wl->wlc, &rs);653spin_unlock_bh(&wl->lock);654if (error)655brcms_err(core, "changing basic rates failed: %d\n",656error);657}658if (changed & BSS_CHANGED_BEACON_INT) {659/* Beacon interval changed */660spin_lock_bh(&wl->lock);661brcms_c_set_beacon_period(wl->wlc, info->beacon_int);662spin_unlock_bh(&wl->lock);663}664if (changed & BSS_CHANGED_BSSID) {665/* BSSID changed, for whatever reason (IBSS and managed mode) */666spin_lock_bh(&wl->lock);667brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);668spin_unlock_bh(&wl->lock);669}670if (changed & BSS_CHANGED_SSID) {671/* BSSID changed, for whatever reason (IBSS and managed mode) */672spin_lock_bh(&wl->lock);673brcms_c_set_ssid(wl->wlc, vif->cfg.ssid, vif->cfg.ssid_len);674spin_unlock_bh(&wl->lock);675}676if (changed & BSS_CHANGED_BEACON) {677/* Beacon data changed, retrieve new beacon (beaconing modes) */678struct sk_buff *beacon;679u16 tim_offset = 0;680681spin_lock_bh(&wl->lock);682beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0);683brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,684info->dtim_period);685spin_unlock_bh(&wl->lock);686}687688if (changed & BSS_CHANGED_AP_PROBE_RESP) {689struct sk_buff *probe_resp;690691spin_lock_bh(&wl->lock);692probe_resp = ieee80211_proberesp_get(hw, vif);693brcms_c_set_new_probe_resp(wl->wlc, probe_resp);694spin_unlock_bh(&wl->lock);695}696697if (changed & BSS_CHANGED_BEACON_ENABLED) {698/* Beaconing should be enabled/disabled (beaconing modes) */699brcms_err(core, "%s: Beacon enabled: %s\n", __func__,700str_true_false(info->enable_beacon));701if (info->enable_beacon &&702hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) {703brcms_c_enable_probe_resp(wl->wlc, true);704} else {705brcms_c_enable_probe_resp(wl->wlc, false);706}707}708709if (changed & BSS_CHANGED_CQM) {710/* Connection quality monitor config changed */711brcms_err(core, "%s: cqm change: threshold %d, hys %d "712" (implement)\n", __func__, info->cqm_rssi_thold,713info->cqm_rssi_hyst);714}715716if (changed & BSS_CHANGED_IBSS) {717/* IBSS join status changed */718brcms_err(core, "%s: IBSS joined: %s (implement)\n",719__func__, str_true_false(vif->cfg.ibss_joined));720}721722if (changed & BSS_CHANGED_ARP_FILTER) {723/* Hardware ARP filter address list or state changed */724brcms_err(core, "%s: arp filtering: %d addresses"725" (implement)\n", __func__, vif->cfg.arp_addr_cnt);726}727728if (changed & BSS_CHANGED_QOS) {729/*730* QoS for this association was enabled/disabled.731* Note that it is only ever disabled for station mode.732*/733brcms_err(core, "%s: qos enabled: %s (implement)\n",734__func__, str_true_false(info->qos));735}736return;737}738739static void740brcms_ops_configure_filter(struct ieee80211_hw *hw,741unsigned int changed_flags,742unsigned int *total_flags, u64 multicast)743{744struct brcms_info *wl = hw->priv;745struct bcma_device *core = wl->wlc->hw->d11core;746747changed_flags &= MAC_FILTERS;748*total_flags &= MAC_FILTERS;749750if (changed_flags & FIF_ALLMULTI)751brcms_dbg_info(core, "FIF_ALLMULTI\n");752if (changed_flags & FIF_FCSFAIL)753brcms_dbg_info(core, "FIF_FCSFAIL\n");754if (changed_flags & FIF_CONTROL)755brcms_dbg_info(core, "FIF_CONTROL\n");756if (changed_flags & FIF_OTHER_BSS)757brcms_dbg_info(core, "FIF_OTHER_BSS\n");758if (changed_flags & FIF_PSPOLL)759brcms_dbg_info(core, "FIF_PSPOLL\n");760if (changed_flags & FIF_BCN_PRBRESP_PROMISC)761brcms_dbg_info(core, "FIF_BCN_PRBRESP_PROMISC\n");762763spin_lock_bh(&wl->lock);764brcms_c_mac_promisc(wl->wlc, *total_flags);765spin_unlock_bh(&wl->lock);766return;767}768769static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw,770struct ieee80211_vif *vif,771const u8 *mac_addr)772{773struct brcms_info *wl = hw->priv;774spin_lock_bh(&wl->lock);775brcms_c_scan_start(wl->wlc);776spin_unlock_bh(&wl->lock);777return;778}779780static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw,781struct ieee80211_vif *vif)782{783struct brcms_info *wl = hw->priv;784spin_lock_bh(&wl->lock);785brcms_c_scan_stop(wl->wlc);786spin_unlock_bh(&wl->lock);787return;788}789790static int791brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,792unsigned int link_id, u16 queue,793const struct ieee80211_tx_queue_params *params)794{795struct brcms_info *wl = hw->priv;796797spin_lock_bh(&wl->lock);798brcms_c_wme_setparams(wl->wlc, queue, params, true);799spin_unlock_bh(&wl->lock);800801return 0;802}803804static int805brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,806struct ieee80211_sta *sta)807{808struct brcms_info *wl = hw->priv;809struct scb *scb = &wl->wlc->pri_scb;810811brcms_c_init_scb(scb);812813wl->pub->global_ampdu = &(scb->scb_ampdu);814wl->pub->global_ampdu->max_pdu = 16;815816/*817* minstrel_ht initiates addBA on our behalf by calling818* ieee80211_start_tx_ba_session()819*/820return 0;821}822823static int824brcms_ops_ampdu_action(struct ieee80211_hw *hw,825struct ieee80211_vif *vif,826struct ieee80211_ampdu_params *params)827{828struct brcms_info *wl = hw->priv;829struct scb *scb = &wl->wlc->pri_scb;830int status;831struct ieee80211_sta *sta = params->sta;832enum ieee80211_ampdu_mlme_action action = params->action;833u16 tid = params->tid;834835if (WARN_ON(scb->magic != SCB_MAGIC))836return -EIDRM;837switch (action) {838case IEEE80211_AMPDU_RX_START:839break;840case IEEE80211_AMPDU_RX_STOP:841break;842case IEEE80211_AMPDU_TX_START:843spin_lock_bh(&wl->lock);844status = brcms_c_aggregatable(wl->wlc, tid);845spin_unlock_bh(&wl->lock);846if (!status) {847brcms_dbg_ht(wl->wlc->hw->d11core,848"START: tid %d is not agg\'able\n", tid);849return -EINVAL;850}851return IEEE80211_AMPDU_TX_START_IMMEDIATE;852853case IEEE80211_AMPDU_TX_STOP_CONT:854case IEEE80211_AMPDU_TX_STOP_FLUSH:855case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:856spin_lock_bh(&wl->lock);857brcms_c_ampdu_flush(wl->wlc, sta, tid);858spin_unlock_bh(&wl->lock);859ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);860break;861case IEEE80211_AMPDU_TX_OPERATIONAL:862/*863* BA window size from ADDBA response ('buf_size') defines how864* many outstanding MPDUs are allowed for the BA stream by865* recipient and traffic class (this is actually unused by the866* rest of the driver). 'ampdu_factor' gives maximum AMPDU size.867*/868spin_lock_bh(&wl->lock);869brcms_c_ampdu_tx_operational(wl->wlc, tid,870(1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +871sta->deflink.ht_cap.ampdu_factor)) - 1);872spin_unlock_bh(&wl->lock);873/* Power save wakeup */874break;875default:876brcms_err(wl->wlc->hw->d11core,877"%s: Invalid command, ignoring\n", __func__);878}879880return 0;881}882883static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)884{885struct brcms_info *wl = hw->priv;886bool blocked;887888spin_lock_bh(&wl->lock);889blocked = brcms_c_check_radio_disabled(wl->wlc);890spin_unlock_bh(&wl->lock);891892wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);893}894895static bool brcms_tx_flush_completed(struct brcms_info *wl)896{897bool result;898899spin_lock_bh(&wl->lock);900result = brcms_c_tx_flush_completed(wl->wlc);901spin_unlock_bh(&wl->lock);902return result;903}904905static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,906u32 queues, bool drop)907{908struct brcms_info *wl = hw->priv;909int ret;910911no_printk("%s: drop = %s\n", __func__, str_true_false(drop));912913ret = wait_event_timeout(wl->tx_flush_wq,914brcms_tx_flush_completed(wl),915msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT));916917brcms_dbg_mac80211(wl->wlc->hw->d11core,918"ret=%d\n", jiffies_to_msecs(ret));919}920921static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)922{923struct brcms_info *wl = hw->priv;924u64 tsf;925926spin_lock_bh(&wl->lock);927tsf = brcms_c_tsf_get(wl->wlc);928spin_unlock_bh(&wl->lock);929930return tsf;931}932933static void brcms_ops_set_tsf(struct ieee80211_hw *hw,934struct ieee80211_vif *vif, u64 tsf)935{936struct brcms_info *wl = hw->priv;937938spin_lock_bh(&wl->lock);939brcms_c_tsf_set(wl->wlc, tsf);940spin_unlock_bh(&wl->lock);941}942943static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw,944struct ieee80211_sta *sta, bool set)945{946struct brcms_info *wl = hw->priv;947struct sk_buff *beacon = NULL;948u16 tim_offset = 0;949950spin_lock_bh(&wl->lock);951if (wl->wlc->vif)952beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif,953&tim_offset, NULL, 0);954if (beacon)955brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,956wl->wlc->vif->bss_conf.dtim_period);957spin_unlock_bh(&wl->lock);958959return 0;960}961962static const struct ieee80211_ops brcms_ops = {963.add_chanctx = ieee80211_emulate_add_chanctx,964.remove_chanctx = ieee80211_emulate_remove_chanctx,965.change_chanctx = ieee80211_emulate_change_chanctx,966.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,967.tx = brcms_ops_tx,968.wake_tx_queue = ieee80211_handle_wake_tx_queue,969.start = brcms_ops_start,970.stop = brcms_ops_stop,971.add_interface = brcms_ops_add_interface,972.remove_interface = brcms_ops_remove_interface,973.config = brcms_ops_config,974.bss_info_changed = brcms_ops_bss_info_changed,975.configure_filter = brcms_ops_configure_filter,976.sw_scan_start = brcms_ops_sw_scan_start,977.sw_scan_complete = brcms_ops_sw_scan_complete,978.conf_tx = brcms_ops_conf_tx,979.sta_add = brcms_ops_sta_add,980.ampdu_action = brcms_ops_ampdu_action,981.rfkill_poll = brcms_ops_rfkill_poll,982.flush = brcms_ops_flush,983.get_tsf = brcms_ops_get_tsf,984.set_tsf = brcms_ops_set_tsf,985.set_tim = brcms_ops_beacon_set_tim,986};987988void brcms_dpc(struct tasklet_struct *t)989{990struct brcms_info *wl;991992wl = from_tasklet(wl, t, tasklet);993994spin_lock_bh(&wl->lock);995996/* call the common second level interrupt handler */997if (wl->pub->up) {998if (wl->resched) {999unsigned long flags;10001001spin_lock_irqsave(&wl->isr_lock, flags);1002brcms_c_intrsupd(wl->wlc);1003spin_unlock_irqrestore(&wl->isr_lock, flags);1004}10051006wl->resched = brcms_c_dpc(wl->wlc, true);1007}10081009/* brcms_c_dpc() may bring the driver down */1010if (!wl->pub->up)1011goto done;10121013/* re-schedule dpc */1014if (wl->resched)1015tasklet_schedule(&wl->tasklet);1016else1017/* re-enable interrupts */1018brcms_intrson(wl);10191020done:1021spin_unlock_bh(&wl->lock);1022wake_up(&wl->tx_flush_wq);1023}10241025static irqreturn_t brcms_isr(int irq, void *dev_id)1026{1027struct brcms_info *wl;1028irqreturn_t ret = IRQ_NONE;10291030wl = (struct brcms_info *) dev_id;10311032spin_lock(&wl->isr_lock);10331034/* call common first level interrupt handler */1035if (brcms_c_isr(wl->wlc)) {1036/* schedule second level handler */1037tasklet_schedule(&wl->tasklet);1038ret = IRQ_HANDLED;1039}10401041spin_unlock(&wl->isr_lock);10421043return ret;1044}10451046/*1047* is called in brcms_pci_probe() context, therefore no locking required.1048*/1049static int ieee_hw_rate_init(struct ieee80211_hw *hw)1050{1051struct brcms_info *wl = hw->priv;1052struct brcms_c_info *wlc = wl->wlc;1053struct ieee80211_supported_band *band;1054u16 phy_type;10551056hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;1057hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;10581059phy_type = brcms_c_get_phy_type(wl->wlc, 0);1060if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {1061band = &wlc->bandstate[BAND_2G_INDEX]->band;1062*band = brcms_band_2GHz_nphy_template;1063if (phy_type == PHY_TYPE_LCN) {1064/* Single stream */1065band->ht_cap.mcs.rx_mask[1] = 0;1066band->ht_cap.mcs.rx_highest = cpu_to_le16(72);1067}1068hw->wiphy->bands[NL80211_BAND_2GHZ] = band;1069} else {1070return -EPERM;1071}10721073/* Assume all bands use the same phy. True for 11n devices. */1074if (wl->pub->_nbands > 1) {1075if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {1076band = &wlc->bandstate[BAND_5G_INDEX]->band;1077*band = brcms_band_5GHz_nphy_template;1078hw->wiphy->bands[NL80211_BAND_5GHZ] = band;1079} else {1080return -EPERM;1081}1082}1083return 0;1084}10851086/*1087* is called in brcms_pci_probe() context, therefore no locking required.1088*/1089static int ieee_hw_init(struct ieee80211_hw *hw)1090{1091ieee80211_hw_set(hw, AMPDU_AGGREGATION);1092ieee80211_hw_set(hw, SIGNAL_DBM);1093ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);1094ieee80211_hw_set(hw, MFP_CAPABLE);10951096hw->extra_tx_headroom = brcms_c_get_header_len();1097hw->queues = N_TX_QUEUES;1098hw->max_rates = 2; /* Primary rate and 1 fallback rate */10991100/* channel change time is dependent on chip and band */1101hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |1102BIT(NL80211_IFTYPE_AP) |1103BIT(NL80211_IFTYPE_ADHOC);11041105/*1106* deactivate sending probe responses by ucude, because this will1107* cause problems when WPS is used.1108*1109* hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;1110*/11111112wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);11131114hw->rate_control_algorithm = "minstrel_ht";11151116hw->sta_data_size = 0;1117return ieee_hw_rate_init(hw);1118}11191120/*1121* attach to the WL device.1122*1123* Attach to the WL device identified by vendor and device parameters.1124* regs is a host accessible memory address pointing to WL device registers.1125*1126* is called in brcms_bcma_probe() context, therefore no locking required.1127*/1128static struct brcms_info *brcms_attach(struct bcma_device *pdev)1129{1130struct brcms_info *wl = NULL;1131int unit, err;1132struct ieee80211_hw *hw;1133u8 perm[ETH_ALEN];11341135unit = n_adapters_found;1136err = 0;11371138if (unit < 0)1139return NULL;11401141/* allocate private info */1142hw = bcma_get_drvdata(pdev);1143if (hw != NULL)1144wl = hw->priv;1145if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL))1146return NULL;1147wl->wiphy = hw->wiphy;11481149atomic_set(&wl->callbacks, 0);11501151init_waitqueue_head(&wl->tx_flush_wq);11521153/* setup the bottom half handler */1154tasklet_setup(&wl->tasklet, brcms_dpc);11551156spin_lock_init(&wl->lock);1157spin_lock_init(&wl->isr_lock);11581159/* common load-time initialization */1160wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err);1161if (!wl->wlc) {1162wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",1163KBUILD_MODNAME, err);1164goto fail;1165}1166wl->pub = brcms_c_pub(wl->wlc);11671168wl->pub->ieee_hw = hw;11691170/* register our interrupt handler */1171if (request_irq(pdev->irq, brcms_isr,1172IRQF_SHARED, KBUILD_MODNAME, wl)) {1173wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);1174goto fail;1175}1176wl->irq = pdev->irq;11771178/* register module */1179brcms_c_module_register(wl->pub, "linux", wl, NULL);11801181if (ieee_hw_init(hw)) {1182wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit,1183__func__);1184goto fail;1185}11861187brcms_c_regd_init(wl->wlc);11881189memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);1190if (WARN_ON(!is_valid_ether_addr(perm)))1191goto fail;1192SET_IEEE80211_PERM_ADDR(hw, perm);11931194err = ieee80211_register_hw(hw);1195if (err)1196wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"1197"%d\n", __func__, err);11981199if (wl->pub->srom_ccode[0] &&1200regulatory_hint(wl->wiphy, wl->pub->srom_ccode))1201wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__);12021203brcms_debugfs_attach(wl->pub);1204brcms_debugfs_create_files(wl->pub);1205n_adapters_found++;1206return wl;12071208fail:1209brcms_free(wl);1210return NULL;1211}1212121312141215/*1216* determines if a device is a WL device, and if so, attaches it.1217*1218* This function determines if a device pointed to by pdev is a WL device,1219* and if so, performs a brcms_attach() on it.1220*1221* Perimeter lock is initialized in the course of this function.1222*/1223static int brcms_bcma_probe(struct bcma_device *pdev)1224{1225struct brcms_info *wl;1226struct ieee80211_hw *hw;1227int ret;12281229dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",1230pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,1231pdev->irq);12321233if ((pdev->id.manuf != BCMA_MANUF_BCM) ||1234(pdev->id.id != BCMA_CORE_80211))1235return -ENODEV;12361237hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);1238if (!hw) {1239pr_err("%s: ieee80211_alloc_hw failed\n", __func__);1240return -ENOMEM;1241}12421243SET_IEEE80211_DEV(hw, &pdev->dev);12441245bcma_set_drvdata(pdev, hw);12461247memset(hw->priv, 0, sizeof(*wl));12481249wl = brcms_attach(pdev);1250if (!wl) {1251pr_err("%s: brcms_attach failed!\n", __func__);1252ret = -ENODEV;1253goto err_free_ieee80211;1254}1255brcms_led_register(wl);12561257return 0;12581259err_free_ieee80211:1260ieee80211_free_hw(hw);1261return ret;1262}12631264static int brcms_suspend(struct bcma_device *pdev)1265{1266struct brcms_info *wl;1267struct ieee80211_hw *hw;12681269hw = bcma_get_drvdata(pdev);1270wl = hw->priv;1271if (!wl) {1272pr_err("%s: %s: no driver private struct!\n", KBUILD_MODNAME,1273__func__);1274return -ENODEV;1275}12761277/* only need to flag hw is down for proper resume */1278spin_lock_bh(&wl->lock);1279wl->pub->hw_up = false;1280spin_unlock_bh(&wl->lock);12811282brcms_dbg_info(wl->wlc->hw->d11core, "brcms_suspend ok\n");12831284return 0;1285}12861287static int brcms_resume(struct bcma_device *pdev)1288{1289return 0;1290}12911292static struct bcma_driver brcms_bcma_driver = {1293.name = KBUILD_MODNAME,1294.probe = brcms_bcma_probe,1295.suspend = brcms_suspend,1296.resume = brcms_resume,1297.remove = brcms_remove,1298.id_table = brcms_coreid_table,1299};13001301/*1302* This is the main entry point for the brcmsmac driver.1303*1304* This function is scheduled upon module initialization and1305* does the driver registration, which result in brcms_bcma_probe()1306* call resulting in the driver bringup.1307*/1308static void brcms_driver_init(struct work_struct *work)1309{1310int error;13111312error = bcma_driver_register(&brcms_bcma_driver);1313if (error)1314pr_err("%s: register returned %d\n", __func__, error);1315}13161317static DECLARE_WORK(brcms_driver_work, brcms_driver_init);13181319static int __init brcms_module_init(void)1320{1321brcms_debugfs_init();1322if (!schedule_work(&brcms_driver_work))1323return -EBUSY;13241325return 0;1326}13271328/*1329* This function unloads the brcmsmac driver from the system.1330*1331* This function unconditionally unloads the brcmsmac driver module from the1332* system.1333*1334*/1335static void __exit brcms_module_exit(void)1336{1337cancel_work_sync(&brcms_driver_work);1338bcma_driver_unregister(&brcms_bcma_driver);1339brcms_debugfs_exit();1340}13411342module_init(brcms_module_init);1343module_exit(brcms_module_exit);13441345/*1346* precondition: perimeter lock has been acquired1347*/1348void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,1349bool state, int prio)1350{1351brcms_err(wl->wlc->hw->d11core, "Shouldn't be here %s\n", __func__);1352}13531354/*1355* precondition: perimeter lock has been acquired1356*/1357void brcms_init(struct brcms_info *wl)1358{1359brcms_dbg_info(wl->wlc->hw->d11core, "Initializing wl%d\n",1360wl->pub->unit);1361brcms_reset(wl);1362brcms_c_init(wl->wlc, wl->mute_tx);1363}13641365/*1366* precondition: perimeter lock has been acquired1367*/1368uint brcms_reset(struct brcms_info *wl)1369{1370brcms_dbg_info(wl->wlc->hw->d11core, "Resetting wl%d\n", wl->pub->unit);1371brcms_c_reset(wl->wlc);13721373/* dpc will not be rescheduled */1374wl->resched = false;13751376/* inform publicly that interface is down */1377wl->pub->up = false;13781379return 0;1380}13811382void brcms_fatal_error(struct brcms_info *wl)1383{1384brcms_err(wl->wlc->hw->d11core, "wl%d: fatal error, reinitializing\n",1385wl->wlc->pub->unit);1386brcms_reset(wl);1387ieee80211_restart_hw(wl->pub->ieee_hw);1388}13891390/*1391* These are interrupt on/off entry points. Disable interrupts1392* during interrupt state transition.1393*/1394void brcms_intrson(struct brcms_info *wl)1395{1396unsigned long flags;13971398spin_lock_irqsave(&wl->isr_lock, flags);1399brcms_c_intrson(wl->wlc);1400spin_unlock_irqrestore(&wl->isr_lock, flags);1401}14021403u32 brcms_intrsoff(struct brcms_info *wl)1404{1405unsigned long flags;1406u32 status;14071408spin_lock_irqsave(&wl->isr_lock, flags);1409status = brcms_c_intrsoff(wl->wlc);1410spin_unlock_irqrestore(&wl->isr_lock, flags);1411return status;1412}14131414void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask)1415{1416unsigned long flags;14171418spin_lock_irqsave(&wl->isr_lock, flags);1419brcms_c_intrsrestore(wl->wlc, macintmask);1420spin_unlock_irqrestore(&wl->isr_lock, flags);1421}14221423/*1424* precondition: perimeter lock has been acquired1425*/1426int brcms_up(struct brcms_info *wl)1427{1428int error = 0;14291430if (wl->pub->up)1431return 0;14321433error = brcms_c_up(wl->wlc);14341435return error;1436}14371438/*1439* precondition: perimeter lock has been acquired1440*/1441void brcms_down(struct brcms_info *wl)1442__must_hold(&wl->lock)1443{1444uint callbacks, ret_val = 0;14451446/* call common down function */1447ret_val = brcms_c_down(wl->wlc);1448callbacks = atomic_read(&wl->callbacks) - ret_val;14491450/* wait for down callbacks to complete */1451spin_unlock_bh(&wl->lock);14521453/* For HIGH_only driver, it's important to actually schedule other work,1454* not just spin wait since everything runs at schedule level1455*/1456SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000);14571458spin_lock_bh(&wl->lock);1459}14601461/*1462* precondition: perimeter lock is not acquired1463*/1464static void _brcms_timer(struct work_struct *work)1465{1466struct brcms_timer *t = container_of(work, struct brcms_timer,1467dly_wrk.work);14681469spin_lock_bh(&t->wl->lock);14701471if (t->set) {1472if (t->periodic) {1473atomic_inc(&t->wl->callbacks);1474ieee80211_queue_delayed_work(t->wl->pub->ieee_hw,1475&t->dly_wrk,1476msecs_to_jiffies(t->ms));1477} else {1478t->set = false;1479}14801481t->fn(t->arg);1482}14831484atomic_dec(&t->wl->callbacks);14851486spin_unlock_bh(&t->wl->lock);1487}14881489/*1490* Adds a timer to the list. Caller supplies a timer function.1491* Is called from wlc.1492*1493* precondition: perimeter lock has been acquired1494*/1495struct brcms_timer *brcms_init_timer(struct brcms_info *wl,1496void (*fn) (void *arg),1497void *arg, const char *name)1498{1499struct brcms_timer *t;15001501t = kzalloc(sizeof(*t), GFP_ATOMIC);1502if (!t)1503return NULL;15041505INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer);1506t->wl = wl;1507t->fn = fn;1508t->arg = arg;1509t->next = wl->timers;1510wl->timers = t;15111512#ifdef DEBUG1513t->name = kstrdup(name, GFP_ATOMIC);1514#endif15151516return t;1517}15181519/*1520* adds only the kernel timer since it's going to be more accurate1521* as well as it's easier to make it periodic1522*1523* precondition: perimeter lock has been acquired1524*/1525void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)1526{1527struct ieee80211_hw *hw = t->wl->pub->ieee_hw;15281529#ifdef DEBUG1530if (t->set)1531brcms_dbg_info(t->wl->wlc->hw->d11core,1532"%s: Already set. Name: %s, per %d\n",1533__func__, t->name, periodic);1534#endif1535t->ms = ms;1536t->periodic = (bool) periodic;1537if (!t->set) {1538t->set = true;1539atomic_inc(&t->wl->callbacks);1540}15411542ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms));1543}15441545/*1546* return true if timer successfully deleted, false if still pending1547*1548* precondition: perimeter lock has been acquired1549*/1550bool brcms_del_timer(struct brcms_timer *t)1551{1552if (t->set) {1553t->set = false;1554if (!cancel_delayed_work(&t->dly_wrk))1555return false;15561557atomic_dec(&t->wl->callbacks);1558}15591560return true;1561}15621563/*1564* precondition: perimeter lock has been acquired1565*/1566void brcms_free_timer(struct brcms_timer *t)1567{1568struct brcms_info *wl = t->wl;1569struct brcms_timer *tmp;15701571/* delete the timer in case it is active */1572brcms_del_timer(t);15731574if (wl->timers == t) {1575wl->timers = wl->timers->next;1576#ifdef DEBUG1577kfree(t->name);1578#endif1579kfree(t);1580return;15811582}15831584tmp = wl->timers;1585while (tmp) {1586if (tmp->next == t) {1587tmp->next = t->next;1588#ifdef DEBUG1589kfree(t->name);1590#endif1591kfree(t);1592return;1593}1594tmp = tmp->next;1595}15961597}15981599/*1600* precondition: no locking required1601*/1602int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)1603{1604int i, entry;1605const u8 *pdata;1606struct firmware_hdr *hdr;1607for (i = 0; i < wl->fw.fw_cnt; i++) {1608hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;1609for (entry = 0; entry < wl->fw.hdr_num_entries[i];1610entry++, hdr++) {1611u32 len = le32_to_cpu(hdr->len);1612if (le32_to_cpu(hdr->idx) == idx) {1613pdata = wl->fw.fw_bin[i]->data +1614le32_to_cpu(hdr->offset);1615*pbuf = kvmemdup(pdata, len, GFP_KERNEL);1616if (*pbuf == NULL)1617return -ENOMEM;1618return 0;1619}1620}1621}1622brcms_err(wl->wlc->hw->d11core,1623"ERROR: ucode buf tag:%d can not be found!\n", idx);1624*pbuf = NULL;1625return -ENODATA;1626}16271628/*1629* Precondition: Since this function is called in brcms_bcma_probe() context,1630* no locking is required.1631*/1632int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)1633{1634int i, entry;1635const u8 *pdata;1636struct firmware_hdr *hdr;1637for (i = 0; i < wl->fw.fw_cnt; i++) {1638hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;1639for (entry = 0; entry < wl->fw.hdr_num_entries[i];1640entry++, hdr++) {1641if (le32_to_cpu(hdr->idx) == idx) {1642pdata = wl->fw.fw_bin[i]->data +1643le32_to_cpu(hdr->offset);1644if (le32_to_cpu(hdr->len) != 4) {1645brcms_err(wl->wlc->hw->d11core,1646"ERROR: fw hdr len\n");1647return -ENOMSG;1648}1649*n_bytes = le32_to_cpu(*((__le32 *) pdata));1650return 0;1651}1652}1653}1654brcms_err(wl->wlc->hw->d11core,1655"ERROR: ucode tag:%d can not be found!\n", idx);1656return -ENOMSG;1657}16581659/*1660* precondition: can both be called locked and unlocked1661*/1662void brcms_ucode_free_buf(void *p)1663{1664kvfree(p);1665}16661667/*1668* checks validity of all firmware images loaded from user space1669*1670* Precondition: Since this function is called in brcms_bcma_probe() context,1671* no locking is required.1672*/1673int brcms_check_firmwares(struct brcms_info *wl)1674{1675int i;1676int entry;1677int rc = 0;1678const struct firmware *fw;1679const struct firmware *fw_hdr;1680struct firmware_hdr *ucode_hdr;1681for (i = 0; i < MAX_FW_IMAGES && rc == 0; i++) {1682fw = wl->fw.fw_bin[i];1683fw_hdr = wl->fw.fw_hdr[i];1684if (fw == NULL && fw_hdr == NULL) {1685break;1686} else if (fw == NULL || fw_hdr == NULL) {1687wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n",1688__func__);1689rc = -EBADF;1690} else if (fw_hdr->size % sizeof(struct firmware_hdr)) {1691wiphy_err(wl->wiphy, "%s: non integral fw hdr file "1692"size %zu/%zu\n", __func__, fw_hdr->size,1693sizeof(struct firmware_hdr));1694rc = -EBADF;1695} else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {1696wiphy_err(wl->wiphy, "%s: out of bounds fw file size %zu\n",1697__func__, fw->size);1698rc = -EBADF;1699} else {1700/* check if ucode section overruns firmware image */1701ucode_hdr = (struct firmware_hdr *)fw_hdr->data;1702for (entry = 0; entry < wl->fw.hdr_num_entries[i] &&1703!rc; entry++, ucode_hdr++) {1704if (le32_to_cpu(ucode_hdr->offset) +1705le32_to_cpu(ucode_hdr->len) >1706fw->size) {1707wiphy_err(wl->wiphy,1708"%s: conflicting bin/hdr\n",1709__func__);1710rc = -EBADF;1711}1712}1713}1714}1715if (rc == 0 && wl->fw.fw_cnt != i) {1716wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__,1717wl->fw.fw_cnt);1718rc = -EBADF;1719}1720return rc;1721}17221723/*1724* precondition: perimeter lock has been acquired1725*/1726bool brcms_rfkill_set_hw_state(struct brcms_info *wl)1727__must_hold(&wl->lock)1728{1729bool blocked = brcms_c_check_radio_disabled(wl->wlc);17301731spin_unlock_bh(&wl->lock);1732wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);1733if (blocked)1734wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy);1735spin_lock_bh(&wl->lock);1736return blocked;1737}173817391740