diff options
Diffstat (limited to 'drivers/staging/brcm80211/brcmsmac/wl_mac80211.c')
-rw-r--r-- | drivers/staging/brcm80211/brcmsmac/wl_mac80211.c | 469 |
1 files changed, 231 insertions, 238 deletions
diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c index c1b07ae31674..6c6236c969b7 100644 --- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c +++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c @@ -30,6 +30,7 @@ #include <bcmdefs.h> #include <bcmwifi.h> #include <bcmutils.h> +#include <bcmnvram.h> #include <pcicfg.h> #include <wlioctl.h> #include <sbhnddma.h> @@ -48,6 +49,8 @@ #include "wl_ucode.h" #include "wl_mac80211.h" +#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ + static void wl_timer(unsigned long data); static void _wl_timer(struct wl_timer *t); @@ -81,6 +84,7 @@ static int __devinit wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void wl_remove(struct pci_dev *pdev); static void wl_free(struct wl_info *wl); +static void wl_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br); MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); @@ -129,7 +133,6 @@ static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw); static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf); static int wl_ops_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); -static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value); static void wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, @@ -147,6 +150,7 @@ static int wl_ops_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size); static void wl_ops_rfkill_poll(struct ieee80211_hw *hw); +static void wl_ops_flush(struct ieee80211_hw *hw, bool drop); static void wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -154,7 +158,7 @@ static void wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) WL_LOCK(wl); if (!wl->pub->up) { - WL_ERROR("ops->tx called while down\n"); + wiphy_err(wl->wiphy, "ops->tx called while down\n"); kfree_skb(skb); goto done; } @@ -169,7 +173,6 @@ static int wl_ops_start(struct ieee80211_hw *hw) bool blocked; /* struct ieee80211_channel *curchan = hw->conf.channel; - WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value); */ ieee80211_wake_queues(hw); @@ -184,10 +187,6 @@ static int wl_ops_start(struct ieee80211_hw *hw) static void wl_ops_stop(struct ieee80211_hw *hw) { -#ifdef BRCMDBG - struct wl_info *wl = hw->priv; - ASSERT(wl); -#endif /*BRCMDBG*/ ieee80211_stop_queues(hw); } @@ -203,8 +202,8 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_WDS && vif->type != NL80211_IFTYPE_ADHOC) { - WL_ERROR("%s: Attempt to add type %d, only STA for now\n", - __func__, vif->type); + wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only" + " STA for now\n", __func__, vif->type); return -EOPNOTSUPP; } @@ -214,7 +213,8 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) WL_UNLOCK(wl); if (err != 0) { - WL_ERROR("%s: wl_up() returned %d\n", __func__, err); + wiphy_err(hw->wiphy, "%s: wl_up() returned %d\n", __func__, + err); } return err; } @@ -249,7 +249,8 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, break; case NL80211_CHAN_HT40MINUS: case NL80211_CHAN_HT40PLUS: - WL_ERROR("%s: Need to implement 40 Mhz Channels!\n", __func__); + wiphy_err(hw->wiphy, + "%s: Need to implement 40 Mhz Channels!\n", __func__); err = 1; break; } @@ -265,39 +266,41 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) struct wl_info *wl = HW_TO_WL(hw); int err = 0; int new_int; + struct wiphy *wiphy = hw->wiphy; WL_LOCK(wl); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { if (wlc_iovar_setint (wl->wlc, "bcn_li_bcn", conf->listen_interval)) { - WL_ERROR("%s: Error setting listen_interval\n", - __func__); + wiphy_err(wiphy, "%s: Error setting listen_interval\n", + __func__); err = -EIO; goto config_out; } wlc_iovar_getint(wl->wlc, "bcn_li_bcn", &new_int); - ASSERT(new_int == conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - WL_ERROR("%s: change monitor mode: %s (implement)\n", __func__, - conf->flags & IEEE80211_CONF_MONITOR ? - "true" : "false"); + wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n", + __func__, conf->flags & IEEE80211_CONF_MONITOR ? + "true" : "false"); if (changed & IEEE80211_CONF_CHANGE_PS) - WL_ERROR("%s: change power-save mode: %s (implement)\n", - __func__, conf->flags & IEEE80211_CONF_PS ? - "true" : "false"); + wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n", + __func__, conf->flags & IEEE80211_CONF_PS ? + "true" : "false"); if (changed & IEEE80211_CONF_CHANGE_POWER) { if (wlc_iovar_setint (wl->wlc, "qtxpower", conf->power_level * 4)) { - WL_ERROR("%s: Error setting power_level\n", __func__); + wiphy_err(wiphy, "%s: Error setting power_level\n", + __func__); err = -EIO; goto config_out; } wlc_iovar_getint(wl->wlc, "qtxpower", &new_int); if (new_int != (conf->power_level * 4)) - WL_ERROR("%s: Power level req != actual, %d %d\n", - __func__, conf->power_level * 4, new_int); + wiphy_err(wiphy, "%s: Power level req != actual, %d %d" + "\n", __func__, conf->power_level * 4, + new_int); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { err = ieee_set_channel(hw, conf->channel, conf->channel_type); @@ -306,13 +309,13 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) if (wlc_set (wl->wlc, WLC_SET_SRL, conf->short_frame_max_tx_count) < 0) { - WL_ERROR("%s: Error setting srl\n", __func__); + wiphy_err(wiphy, "%s: Error setting srl\n", __func__); err = -EIO; goto config_out; } if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count) < 0) { - WL_ERROR("%s: Error setting lrl\n", __func__); + wiphy_err(wiphy, "%s: Error setting lrl\n", __func__); err = -EIO; goto config_out; } @@ -329,25 +332,18 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u32 changed) { struct wl_info *wl = HW_TO_WL(hw); + struct wiphy *wiphy = hw->wiphy; int val; if (changed & BSS_CHANGED_ASSOC) { /* association status changed (associated/disassociated) * also implies a change in the AID. */ - WL_ERROR("%s: %s: %sassociated\n", KBUILD_MODNAME, __func__, - info->assoc ? "" : "dis"); + wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME, + __func__, info->assoc ? "" : "dis"); + WL_LOCK(wl); wlc_associate_upd(wl->wlc, info->assoc); - } - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - /* CTS protection changed */ - WL_ERROR("%s: use_cts_prot: %s (implement)\n", __func__, - info->use_cts_prot ? "true" : "false"); - } - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - /* preamble changed */ - WL_ERROR("%s: short preamble: %s (implement)\n", __func__, - info->use_short_preamble ? "true" : "false"); + WL_UNLOCK(wl); } if (changed & BSS_CHANGED_ERP_SLOT) { /* slot timing changed */ @@ -363,29 +359,57 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_HT) { /* 802.11n parameters changed */ u16 mode = info->ht_operation_mode; - WL_NONE("%s: HT mode: 0x%04X\n", __func__, mode); + + WL_LOCK(wl); wlc_protection_upd(wl->wlc, WLC_PROT_N_CFG, mode & IEEE80211_HT_OP_MODE_PROTECTION); wlc_protection_upd(wl->wlc, WLC_PROT_N_NONGF, mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); wlc_protection_upd(wl->wlc, WLC_PROT_N_OBSS, mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT); + WL_UNLOCK(wl); } if (changed & BSS_CHANGED_BASIC_RATES) { - /* Basic rateset changed */ - WL_ERROR("%s: Need to change Basic Rates: 0x%x (implement)\n", - __func__, (u32) info->basic_rates); + struct ieee80211_supported_band *bi; + u32 br_mask, i; + u16 rate; + struct wl_rateset rs; + int error; + + /* retrieve the current rates */ + WL_LOCK(wl); + error = wlc_ioctl(wl->wlc, WLC_GET_CURR_RATESET, + &rs, sizeof(rs), NULL); + WL_UNLOCK(wl); + if (error) { + wiphy_err(wiphy, "%s: retrieve rateset failed: %d\n", + __func__, error); + return; + } + br_mask = info->basic_rates; + bi = hw->wiphy->bands[wlc_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 */ + wl_set_basic_rate(&rs, rate, br_mask & 1); + br_mask >>= 1; + } + + /* update the rate set */ + WL_LOCK(wl); + wlc_ioctl(wl->wlc, WLC_SET_RATESET, &rs, sizeof(rs), NULL); + WL_UNLOCK(wl); } if (changed & BSS_CHANGED_BEACON_INT) { /* Beacon interval changed */ - WL_NONE("%s: Beacon Interval: %d\n", - __func__, info->beacon_int); + WL_LOCK(wl); wlc_set(wl->wlc, WLC_SET_BCNPRD, info->beacon_int); + WL_UNLOCK(wl); } if (changed & BSS_CHANGED_BSSID) { /* BSSID changed, for whatever reason (IBSS and managed mode) */ - WL_NONE("%s: new BSSID: aid %d bss:%pM\n", __func__, - info->aid, info->bssid); WL_LOCK(wl); wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); @@ -393,41 +417,42 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) { /* Beacon data changed, retrieve new beacon (beaconing modes) */ - WL_ERROR("%s: beacon changed\n", __func__); + wiphy_err(wiphy, "%s: beacon changed\n", __func__); } if (changed & BSS_CHANGED_BEACON_ENABLED) { /* Beaconing should be enabled/disabled (beaconing modes) */ - WL_ERROR("%s: Beacon enabled: %s\n", __func__, - info->enable_beacon ? "true" : "false"); + wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__, + info->enable_beacon ? "true" : "false"); } if (changed & BSS_CHANGED_CQM) { /* Connection quality monitor config changed */ - WL_ERROR("%s: cqm change: threshold %d, hys %d (implement)\n", - __func__, info->cqm_rssi_thold, info->cqm_rssi_hyst); + wiphy_err(wiphy, "%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 */ - WL_ERROR("%s: IBSS joined: %s (implement)\n", __func__, - info->ibss_joined ? "true" : "false"); + wiphy_err(wiphy, "%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 */ - WL_ERROR("%s: arp filtering: enabled %s, count %d (implement)\n", - __func__, info->arp_filter_enabled ? "true" : "false", - info->arp_addr_cnt); + wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d" + " (implement)\n", __func__, info->arp_filter_enabled ? + "true" : "false", 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. */ - WL_ERROR("%s: qos enabled: %s (implement)\n", __func__, - info->qos ? "true" : "false"); + wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__, + info->qos ? "true" : "false"); } if (changed & BSS_CHANGED_IDLE) { /* Idle changed for this BSS/interface */ - WL_ERROR("%s: BSS idle: %s (implement)\n", __func__, - info->idle ? "true" : "false"); + wiphy_err(wiphy, "%s: BSS idle: %s (implement)\n", __func__, + info->idle ? "true" : "false"); } return; } @@ -438,23 +463,23 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { struct wl_info *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; if (changed_flags & FIF_PROMISC_IN_BSS) - WL_ERROR("FIF_PROMISC_IN_BSS\n"); + wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n"); if (changed_flags & FIF_ALLMULTI) - WL_ERROR("FIF_ALLMULTI\n"); + wiphy_err(wiphy, "FIF_ALLMULTI\n"); if (changed_flags & FIF_FCSFAIL) - WL_ERROR("FIF_FCSFAIL\n"); + wiphy_err(wiphy, "FIF_FCSFAIL\n"); if (changed_flags & FIF_PLCPFAIL) - WL_ERROR("FIF_PLCPFAIL\n"); + wiphy_err(wiphy, "FIF_PLCPFAIL\n"); if (changed_flags & FIF_CONTROL) - WL_ERROR("FIF_CONTROL\n"); + wiphy_err(wiphy, "FIF_CONTROL\n"); if (changed_flags & FIF_OTHER_BSS) - WL_ERROR("FIF_OTHER_BSS\n"); + wiphy_err(wiphy, "FIF_OTHER_BSS\n"); if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - WL_NONE("FIF_BCN_PRBRESP_PROMISC\n"); WL_LOCK(wl); if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; @@ -471,14 +496,12 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, static int wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { - WL_NONE("%s: Enter\n", __func__); return 0; } static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) { struct wl_info *wl = hw->priv; - WL_NONE("Scan Start\n"); WL_LOCK(wl); wlc_scan_start(wl->wlc); WL_UNLOCK(wl); @@ -488,7 +511,6 @@ static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) { struct wl_info *wl = hw->priv; - WL_NONE("Scan Complete\n"); WL_LOCK(wl); wlc_scan_stop(wl->wlc); WL_UNLOCK(wl); @@ -497,7 +519,7 @@ static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) { - WL_ERROR("%s: Enter\n", __func__); + wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return; } @@ -510,20 +532,10 @@ wl_ops_get_stats(struct ieee80211_hw *hw, WL_LOCK(wl); cnt = wl->pub->_cnt; - stats->dot11ACKFailureCount = cnt->txnoack; - stats->dot11RTSFailureCount = cnt->txnocts; - stats->dot11FCSErrorCount = cnt->rxcrc; - stats->dot11RTSSuccessCount = cnt->txrts; - WL_UNLOCK(wl); - return 0; -} - -static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl_info *wl = hw->priv; - - WL_LOCK(wl); - wlc_iovar_setint(wl->wlc, "rtsthresh", value & 0xFFFF); + stats->dot11ACKFailureCount = 0; + stats->dot11RTSFailureCount = 0; + stats->dot11FCSErrorCount = 0; + stats->dot11RTSSuccessCount = 0; WL_UNLOCK(wl); return 0; } @@ -532,10 +544,10 @@ static void wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - WL_NONE("%s: Enter\n", __func__); switch (cmd) { default: - WL_ERROR("%s: Unknown cmd = %d\n", __func__, cmd); + wiphy_err(hw->wiphy, "%s: Unknown cmd = %d\n", __func__, + cmd); break; } return; @@ -547,12 +559,8 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, { struct wl_info *wl = hw->priv; - WL_NONE("%s: Enter (WME config)\n", __func__); - WL_NONE("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, - params->txop, params->cw_min, params->cw_max, params->aifs); - WL_LOCK(wl); - wlc_wme_setparams(wl->wlc, queue, (void *)params, true); + wlc_wme_setparams(wl->wlc, queue, params, true); WL_UNLOCK(wl); return 0; @@ -560,7 +568,7 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, static u64 wl_ops_get_tsf(struct ieee80211_hw *hw) { - WL_ERROR("%s: Enter\n", __func__); + wiphy_err(hw->wiphy, "%s: Enter\n", __func__); return 0; } @@ -585,7 +593,7 @@ wl_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wl->pub->global_ampdu = &(scb->scb_ampdu); wl->pub->global_ampdu->scb = scb; wl->pub->global_ampdu->max_pdu = 16; - pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID, + bcm_pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID, AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT); sta->ht_cap.ht_supported = true; @@ -603,7 +611,6 @@ static int wl_ops_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - WL_NONE("%s: Enter\n", __func__); return 0; } @@ -614,27 +621,25 @@ wl_ops_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { -#if defined(BCMDBG) struct scb *scb = (struct scb *)sta->drv_priv; -#endif struct wl_info *wl = hw->priv; int status; - ASSERT(scb->magic == SCB_MAGIC); + if (WARN_ON(scb->magic != SCB_MAGIC)) + return -EIDRM; switch (action) { case IEEE80211_AMPDU_RX_START: - WL_NONE("%s: action = IEEE80211_AMPDU_RX_START\n", __func__); break; case IEEE80211_AMPDU_RX_STOP: - WL_NONE("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__); break; case IEEE80211_AMPDU_TX_START: WL_LOCK(wl); status = wlc_aggregatable(wl->wlc, tid); WL_UNLOCK(wl); if (!status) { - /* WL_ERROR("START: tid %d is not agg' able, return FAILURE to stack\n", tid); */ - return -1; + wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n", + tid); + return -EINVAL; } /* XXX: Use the starting sequence number provided ... */ *ssn = 0; @@ -650,11 +655,10 @@ wl_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_OPERATIONAL: /* Not sure what to do here */ /* Power save wakeup */ - WL_NONE("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n", - __func__); break; default: - WL_ERROR("%s: Invalid command, ignoring\n", __func__); + wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n", + __func__); } return 0; @@ -669,10 +673,21 @@ static void wl_ops_rfkill_poll(struct ieee80211_hw *hw) blocked = wlc_check_radio_disabled(wl->wlc); WL_UNLOCK(wl); - WL_NONE("wl: rfkill_poll: %d\n", blocked); wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); } +static void wl_ops_flush(struct ieee80211_hw *hw, bool drop) +{ + struct wl_info *wl = HW_TO_WL(hw); + + no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); + + /* wait for packet queue and dma fifos to run empty */ + WL_LOCK(wl); + wlc_wait_for_tx_completion(wl->wlc, drop); + WL_UNLOCK(wl); +} + static const struct ieee80211_ops wl_ops = { .tx = wl_ops_tx, .start = wl_ops_start, @@ -687,7 +702,6 @@ static const struct ieee80211_ops wl_ops = { .sw_scan_complete = wl_ops_sw_scan_complete, .set_tsf = wl_ops_set_tsf, .get_stats = wl_ops_get_stats, - .set_rts_threshold = wl_ops_set_rts_threshold, .sta_notify = wl_ops_sta_notify, .conf_tx = wl_ops_conf_tx, .get_tsf = wl_ops_get_tsf, @@ -695,6 +709,7 @@ static const struct ieee80211_ops wl_ops = { .sta_remove = wl_ops_sta_remove, .ampdu_action = wl_ops_ampdu_action, .rfkill_poll = wl_ops_rfkill_poll, + .flush = wl_ops_flush, }; /* @@ -702,8 +717,6 @@ static const struct ieee80211_ops wl_ops = { */ static int wl_set_hint(struct wl_info *wl, char *abbrev) { - WL_NONE("%s: Sending country code %c%c to MAC80211\n", - __func__, abbrev[0], abbrev[1]); return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); } @@ -724,7 +737,7 @@ static int wl_set_hint(struct wl_info *wl, char *abbrev) static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, uint bustype, void *btparam, uint irq) { - struct wl_info *wl; + struct wl_info *wl = NULL; int unit, err; unsigned long base_addr; @@ -735,14 +748,16 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, err = 0; if (unit < 0) { - WL_ERROR("wl%d: unit number overflow, exiting\n", unit); return NULL; } /* allocate private info */ hw = pci_get_drvdata(btparam); /* btparam == pdev */ - wl = hw->priv; - ASSERT(wl); + if (hw != NULL) + wl = hw->priv; + if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) + return NULL; + wl->wiphy = hw->wiphy; atomic_set(&wl->callbacks, 0); @@ -759,13 +774,13 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, /* Do nothing */ } else { bustype = PCI_BUS; - WL_TRACE("force to PCI\n"); + BCMMSG(wl->wiphy, "force to PCI\n"); } wl->bcm_bustype = bustype; wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); if (wl->regsva == NULL) { - WL_ERROR("wl%d: ioremap() failed\n", unit); + wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit); goto fail; } spin_lock_init(&wl->lock); @@ -773,11 +788,11 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, /* prepare ucode */ if (wl_request_fw(wl, (struct pci_dev *)btparam) < 0) { - WL_ERROR("%s: Failed to find firmware usually in %s\n", - KBUILD_MODNAME, "/lib/firmware/brcm"); + wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " + "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); wl_release_fw(wl); wl_remove((struct pci_dev *)btparam); - goto fail1; + return NULL; } /* common load-time initialization */ @@ -785,24 +800,22 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, wl->regsva, wl->bcm_bustype, btparam, &err); wl_release_fw(wl); if (!wl->wlc) { - WL_ERROR("%s: wlc_attach() failed with code %d\n", - KBUILD_MODNAME, err); + wiphy_err(wl->wiphy, "%s: wlc_attach() failed with code %d\n", + KBUILD_MODNAME, err); goto fail; } wl->pub = wlc_pub(wl->wlc); wl->pub->ieee_hw = hw; - ASSERT(wl->pub->ieee_hw); - ASSERT(wl->pub->ieee_hw->priv == wl); - if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { - WL_ERROR("wl%d: Error setting MPC variable to 0\n", unit); + wiphy_err(wl->wiphy, "wl%d: Error setting MPC variable to 0\n", + unit); } /* register our interrupt handler */ if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { - WL_ERROR("wl%d: request_irq() failed\n", unit); + wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); goto fail; } wl->irq = irq; @@ -812,18 +825,20 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, NULL); if (ieee_hw_init(hw)) { - WL_ERROR("wl%d: %s: ieee_hw_init failed!\n", unit, __func__); + wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, + __func__); goto fail; } memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); - ASSERT(is_valid_ether_addr(perm)); + if (WARN_ON(!is_valid_ether_addr(perm))) + goto fail; SET_IEEE80211_PERM_ADDR(hw, perm); err = ieee80211_register_hw(hw); if (err) { - WL_ERROR("%s: ieee80211_register_hw failed, status %d\n", - __func__, err); + wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" + "%d\n", __func__, err); } if (wl->pub->srom_ccode[0]) @@ -831,8 +846,8 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, else err = wl_set_hint(wl, "US"); if (err) { - WL_ERROR("%s: regulatory_hint failed, status %d\n", - __func__, err); + wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", + __func__, err); } wl_found++; @@ -840,7 +855,6 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, fail: wl_free(wl); -fail1: return NULL; } @@ -1027,9 +1041,8 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) { - WL_ERROR("Phy list failed\n"); + wiphy_err(hw->wiphy, "Phy list failed\n"); } - WL_NONE("%s: phylist = %c\n", __func__, phy_list[0]); if (phy_list[0] == 'n' || phy_list[0] == 'c') { if (phy_list[0] == 'c') { @@ -1039,8 +1052,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) } hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy; } else { - BUG(); - return -1; + return -EPERM; } /* Assume all bands use the same phy. True for 11n devices. */ @@ -1050,12 +1062,9 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl_band_5GHz_nphy; } else { - return -1; + return -EPERM; } } - - WL_NONE("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g); - return 0; } @@ -1070,8 +1079,7 @@ static int ieee_hw_init(struct ieee80211_hw *hw) | IEEE80211_HW_AMPDU_AGGREGATION; hw->extra_tx_headroom = wlc_get_header_len(); - /* FIXME: should get this from wlc->machwcap */ - hw->queues = 4; + hw->queues = N_TX_QUEUES; /* FIXME: this doesn't seem to be used properly in minstrel_ht. * mac80211/status.c:ieee80211_tx_status() checks this value, * but mac80211/rc80211_minstrel_ht.c:minstrel_ht_get_rate() @@ -1104,11 +1112,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct ieee80211_hw *hw; u32 val; - ASSERT(pdev); - - WL_TRACE("%s: bus %d slot %d func %d irq %d\n", - __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq); + dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || (((pdev->device & 0xff00) != 0x4300) && @@ -1118,9 +1124,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pci_enable_device(pdev); if (rc) { - WL_ERROR("%s: Cannot enable device %d-%d_%d\n", - __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); + pr_err("%s: Cannot enable device %d-%d_%d\n", + __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); return -ENODEV; } pci_set_master(pdev); @@ -1131,9 +1137,8 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops); if (!hw) { - WL_ERROR("%s: ieee80211_alloc_hw failed\n", __func__); - rc = -ENOMEM; - goto err_1; + pr_err("%s: ieee80211_alloc_hw failed\n", __func__); + return -ENOMEM; } SET_IEEE80211_DEV(hw, &pdev->dev); @@ -1146,14 +1151,11 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) PCI_BUS, pdev, pdev->irq); if (!wl) { - WL_ERROR("%s: %s: wl_attach failed!\n", - KBUILD_MODNAME, __func__); + pr_err("%s: %s: wl_attach failed!\n", KBUILD_MODNAME, + __func__); return -ENODEV; } return 0; - err_1: - WL_ERROR("%s: err_1: Major hoarkage\n", __func__); - return 0; } static int wl_suspend(struct pci_dev *pdev, pm_message_t state) @@ -1161,12 +1163,11 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state) struct wl_info *wl; struct ieee80211_hw *hw; - WL_TRACE("wl: wl_suspend\n"); - hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR("wl: wl_suspend: pci_get_drvdata failed\n"); + wiphy_err(wl->wiphy, + "wl_suspend: pci_get_drvdata failed\n"); return -ENODEV; } @@ -1187,11 +1188,11 @@ static int wl_resume(struct pci_dev *pdev) int err = 0; u32 val; - WL_TRACE("wl: wl_resume\n"); hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR("wl: wl_resume: pci_get_drvdata failed\n"); + wiphy_err(wl->wiphy, + "wl: wl_resume: pci_get_drvdata failed\n"); return -ENODEV; } @@ -1231,7 +1232,7 @@ static void wl_remove(struct pci_dev *pdev) hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n"); + pr_err("wl: wl_remove: pci_get_drvdata failed\n"); return; } @@ -1239,7 +1240,7 @@ static void wl_remove(struct pci_dev *pdev) status = wlc_chipmatch(pdev->vendor, pdev->device); WL_UNLOCK(wl); if (!status) { - WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n"); + wiphy_err(wl->wiphy, "wl: wl_remove: wlc_chipmatch failed\n"); return; } if (wl->wlc) { @@ -1249,7 +1250,6 @@ static void wl_remove(struct pci_dev *pdev) WL_LOCK(wl); wl_down(wl); WL_UNLOCK(wl); - WL_NONE("%s: Down\n", __func__); } pci_disable_device(pdev); @@ -1342,7 +1342,6 @@ static void wl_free(struct wl_info *wl) { struct wl_timer *t, *next; - ASSERT(wl); /* free ucode data */ if (wl->fw.fw_cnt) wl_ucode_data_free(); @@ -1389,13 +1388,30 @@ static void wl_free(struct wl_info *wl) wl->regsva = NULL; } +/* flags the given rate in rateset as requested */ +static void wl_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br) +{ + u32 i; + + for (i = 0; i < rs->count; i++) { + if (rate != (rs->rates[i] & 0x7f)) + continue; + + if (is_br) + rs->rates[i] |= WLC_RATE_FLAG; + else + rs->rates[i] &= WLC_RATE_MASK; + return; + } +} + /* * precondition: perimeter lock has been acquired */ void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, int prio) { - WL_ERROR("Shouldn't be here %s\n", __func__); + wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__); } /* @@ -1403,8 +1419,7 @@ void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, */ void wl_init(struct wl_info *wl) { - WL_TRACE("wl%d: wl_init\n", wl->pub->unit); - + BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit); wl_reset(wl); wlc_init(wl->wlc); @@ -1415,8 +1430,7 @@ void wl_init(struct wl_info *wl) */ uint wl_reset(struct wl_info *wl) { - WL_TRACE("wl%d: wl_reset\n", wl->pub->unit); - + BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit); wlc_reset(wl->wlc); /* dpc will not be rescheduled */ @@ -1429,7 +1443,7 @@ uint wl_reset(struct wl_info *wl) * These are interrupt on/off entry points. Disable interrupts * during interrupt state transition. */ -void BCMFASTPATH wl_intrson(struct wl_info *wl) +void wl_intrson(struct wl_info *wl) { unsigned long flags; @@ -1446,7 +1460,7 @@ bool wl_alloc_dma_resources(struct wl_info *wl, uint addrwidth) return true; } -u32 BCMFASTPATH wl_intrsoff(struct wl_info *wl) +u32 wl_intrsoff(struct wl_info *wl) { unsigned long flags; u32 status; @@ -1503,7 +1517,7 @@ void wl_down(struct wl_info *wl) WL_LOCK(wl); } -static irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) +static irqreturn_t wl_isr(int irq, void *dev_id) { struct wl_info *wl; bool ours, wantdpc; @@ -1521,7 +1535,6 @@ static irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) /* ...and call the second level interrupt handler */ /* schedule dpc */ - ASSERT(wl->resched == false); tasklet_schedule(&wl->tasklet); } } @@ -1531,7 +1544,7 @@ static irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) return IRQ_RETVAL(ours); } -static void BCMFASTPATH wl_dpc(unsigned long data) +static void wl_dpc(unsigned long data) { struct wl_info *wl; @@ -1613,7 +1626,8 @@ struct wl_timer *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), t = kzalloc(sizeof(struct wl_timer), GFP_ATOMIC); if (!t) { - WL_ERROR("wl%d: wl_init_timer: out of memory\n", wl->pub->unit); + wiphy_err(wl->wiphy, "wl%d: wl_init_timer: out of memory\n", + wl->pub->unit); return 0; } @@ -1644,12 +1658,10 @@ void wl_add_timer(struct wl_info *wl, struct wl_timer *t, uint ms, int periodic) { #ifdef BCMDBG if (t->set) { - WL_ERROR("%s: Already set. Name: %s, per %d\n", - __func__, t->name, periodic); + wiphy_err(wl->wiphy, "%s: Already set. Name: %s, per %d\n", + __func__, t->name, periodic); } #endif - ASSERT(!t->set); - t->ms = ms; t->periodic = (bool) periodic; t->set = true; @@ -1719,37 +1731,6 @@ void wl_free_timer(struct wl_info *wl, struct wl_timer *t) */ static int wl_linux_watchdog(void *ctx) { - struct wl_info *wl = (struct wl_info *) ctx; - struct wl_cnt *cnt; - struct net_device_stats *stats = NULL; - uint id; - /* refresh stats */ - if (wl->pub->up) { - ASSERT(wl->stats_id < 2); - - cnt = wl->pub->_cnt; - id = 1 - wl->stats_id; - stats = &wl->stats_watchdog[id]; - stats->rx_packets = cnt->rxframe; - stats->tx_packets = cnt->txframe; - stats->rx_bytes = cnt->rxbyte; - stats->tx_bytes = cnt->txbyte; - stats->rx_errors = cnt->rxerror; - stats->tx_errors = cnt->txerror; - stats->collisions = 0; - - stats->rx_length_errors = 0; - stats->rx_over_errors = cnt->rxoflo; - stats->rx_crc_errors = cnt->rxcrc; - stats->rx_frame_errors = 0; - stats->rx_fifo_errors = cnt->rxoflo; - stats->rx_missed_errors = 0; - - stats->tx_fifo_errors = cnt->txuflo; - - wl->stats_id = id; - } - return 0; } @@ -1780,8 +1761,8 @@ int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx) pdata = wl->fw.fw_bin[i]->data + hdr->offset; *pbuf = kmalloc(hdr->len, GFP_ATOMIC); if (*pbuf == NULL) { - WL_ERROR("fail to alloc %d bytes\n", - hdr->len); + wiphy_err(wl->wiphy, "fail to alloc %d" + " bytes\n", hdr->len); goto fail; } memcpy(*pbuf, pdata, hdr->len); @@ -1789,10 +1770,11 @@ int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx) } } } - WL_ERROR("ERROR: ucode buf tag:%d can not be found!\n", idx); + wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n", + idx); *pbuf = NULL; fail: - return BCME_NOTFOUND; + return -ENODATA; } /* @@ -1810,14 +1792,18 @@ int wl_ucode_init_uint(struct wl_info *wl, u32 *data, u32 idx) entry++, hdr++) { if (hdr->idx == idx) { pdata = wl->fw.fw_bin[i]->data + hdr->offset; - ASSERT(hdr->len == 4); + if (hdr->len != 4) { + wiphy_err(wl->wiphy, + "ERROR: fw hdr len\n"); + return -ENOMSG; + } *data = *((u32 *) pdata); return 0; } } } - WL_ERROR("ERROR: ucode tag:%d can not be found!\n", idx); - return -1; + wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx); + return -ENOMSG; } /* @@ -1837,26 +1823,22 @@ static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) break; sprintf(fw_name, "%s-%d.fw", wl_firmwares[i], UCODE_LOADER_API_VER); - WL_NONE("request fw %s\n", fw_name); status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); if (status) { - WL_ERROR("%s: fail to load firmware %s\n", - KBUILD_MODNAME, fw_name); + wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", + KBUILD_MODNAME, fw_name); return status; } - WL_NONE("request fw %s\n", fw_name); sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i], UCODE_LOADER_API_VER); status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); if (status) { - WL_ERROR("%s: fail to load firmware %s\n", - KBUILD_MODNAME, fw_name); + wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", + KBUILD_MODNAME, fw_name); return status; } wl->fw.hdr_num_entries[i] = wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr)); - WL_NONE("request fw %s find: %d entries\n", - fw_name, wl->fw.hdr_num_entries[i]); } wl->fw.fw_cnt = i; return wl_ucode_data_init(wl); @@ -1904,16 +1886,17 @@ int wl_check_firmwares(struct wl_info *wl) if (fw == NULL && fw_hdr == NULL) { break; } else if (fw == NULL || fw_hdr == NULL) { - WL_ERROR("%s: invalid bin/hdr fw\n", __func__); + wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n", + __func__); rc = -EBADF; } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) { - WL_ERROR("%s: non integral fw hdr file size %zu/%zu\n", - __func__, fw_hdr->size, - sizeof(struct wl_fw_hdr)); + wiphy_err(wl->wiphy, "%s: non integral fw hdr file " + "size %zu/%zu\n", __func__, fw_hdr->size, + sizeof(struct wl_fw_hdr)); rc = -EBADF; } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { - WL_ERROR("%s: out of bounds fw file size %zu\n", - __func__, fw->size); + wiphy_err(wl->wiphy, "%s: out of bounds fw file size " + "%zu\n", __func__, fw->size); rc = -EBADF; } else { /* check if ucode section overruns firmware image */ @@ -1922,15 +1905,17 @@ int wl_check_firmwares(struct wl_info *wl) !rc; entry++, ucode_hdr++) { if (ucode_hdr->offset + ucode_hdr->len > fw->size) { - WL_ERROR("%s: conflicting bin/hdr\n", - __func__); + wiphy_err(wl->wiphy, + "%s: conflicting bin/hdr\n", + __func__); rc = -EBADF; } } } } if (rc == 0 && wl->fw.fw_cnt != i) { - WL_ERROR("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt); + wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__, + wl->fw.fw_cnt); rc = -EBADF; } return rc; @@ -1943,8 +1928,6 @@ bool wl_rfkill_set_hw_state(struct wl_info *wl) { bool blocked = wlc_check_radio_disabled(wl->wlc); - WL_NONE("%s: update hw state: blocked=%s\n", __func__, - blocked ? "true" : "false"); WL_UNLOCK(wl); wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); if (blocked) @@ -1952,3 +1935,13 @@ bool wl_rfkill_set_hw_state(struct wl_info *wl) WL_LOCK(wl); return blocked; } + +/* + * precondition: perimeter lock has been acquired + */ +void wl_msleep(struct wl_info *wl, uint ms) +{ + WL_UNLOCK(wl); + msleep(ms); + WL_LOCK(wl); +} |