mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 11:16:11 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
4ba3eb034f
125 changed files with 3168 additions and 1941 deletions
|
@ -850,6 +850,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
|
|||
}
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||
switch (head->plcp[0] & 0xf) {
|
||||
case 0xb:
|
||||
|
@ -897,8 +898,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
|
|||
status->flag |= RX_FLAG_HT;
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
/* XXX */
|
||||
default:
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: invalid modulation\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
|
@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
|||
}
|
||||
|
||||
static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
{
|
||||
|
@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
|||
tid_info->state = AR9170_TID_STATE_PROGRESS;
|
||||
tid_info->active = false;
|
||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
|
@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
|||
tid_info->active = false;
|
||||
skb_queue_purge(&tid_info->queue);
|
||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
|
|
|
@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
|||
{ USB_DEVICE(0x0cf3, 0x1002) },
|
||||
/* Cace Airpcap NX */
|
||||
{ USB_DEVICE(0xcace, 0x0300) },
|
||||
/* D-Link DWA 160A */
|
||||
/* D-Link DWA 160 A1 */
|
||||
{ USB_DEVICE(0x07d1, 0x3c10) },
|
||||
/* D-Link DWA 160 A2 */
|
||||
{ USB_DEVICE(0x07d1, 0x3a09) },
|
||||
/* Netgear WNDA3100 */
|
||||
{ USB_DEVICE(0x0846, 0x9010) },
|
||||
/* Netgear WN111 v2 */
|
||||
|
|
|
@ -1399,7 +1399,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
|||
if (i_coffd == 0 || q_coffd == 0)
|
||||
goto done;
|
||||
|
||||
i_coff = ((-iq_corr) / i_coffd) & 0x3f;
|
||||
i_coff = ((-iq_corr) / i_coffd);
|
||||
|
||||
/* Boundary check */
|
||||
if (i_coff > 31)
|
||||
|
@ -1407,7 +1407,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
|||
if (i_coff < -32)
|
||||
i_coff = -32;
|
||||
|
||||
q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
|
||||
q_coff = (((s32)i_pwr / q_coffd) - 128);
|
||||
|
||||
/* Boundary check */
|
||||
if (q_coff > 15)
|
||||
|
|
|
@ -198,18 +198,8 @@ struct ath_txq {
|
|||
struct list_head axq_q;
|
||||
spinlock_t axq_lock;
|
||||
u32 axq_depth;
|
||||
u8 axq_aggr_depth;
|
||||
bool stopped;
|
||||
bool axq_tx_inprogress;
|
||||
struct ath_buf *axq_linkbuf;
|
||||
|
||||
/* first desc of the last descriptor that contains CTS */
|
||||
struct ath_desc *axq_lastdsWithCTS;
|
||||
|
||||
/* final desc of the gating desc that determines whether
|
||||
lastdsWithCTS has been DMA'ed or not */
|
||||
struct ath_desc *axq_gatingds;
|
||||
|
||||
struct list_head axq_acq;
|
||||
};
|
||||
|
||||
|
|
|
@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
|
|||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int hdrlen, padsize;
|
||||
int hdrlen, padpos, padsize;
|
||||
u8 keyix;
|
||||
__le16 fc;
|
||||
|
||||
/* see if any padding is done by the hw and remove it */
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
padpos = 24;
|
||||
fc = hdr->frame_control;
|
||||
if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
|
||||
cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
|
||||
padpos += 6; /* ETH_ALEN */
|
||||
}
|
||||
if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
|
||||
cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
|
||||
padpos += 2;
|
||||
}
|
||||
|
||||
/* The MAC header is padded to have 32-bit boundary if the
|
||||
* packet payload is non-zero. The general calculation for
|
||||
* padsize would take into account odd header lengths:
|
||||
* padsize = (4 - hdrlen % 4) % 4; However, since only
|
||||
* padsize = (4 - padpos % 4) % 4; However, since only
|
||||
* even-length headers are used, padding can only be 0 or 2
|
||||
* bytes and we can optimize this a bit. In addition, we must
|
||||
* not try to remove padding from short control frames that do
|
||||
* not have payload. */
|
||||
padsize = hdrlen & 3;
|
||||
if (padsize && hdrlen >= 24) {
|
||||
memmove(skb->data + padsize, skb->data, hdrlen);
|
||||
padsize = padpos & 3;
|
||||
if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
|
||||
memmove(skb->data + padsize, skb->data, padpos);
|
||||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ struct ath_buf {
|
|||
u16 bf_flags;
|
||||
struct ath_buf_state bf_state;
|
||||
dma_addr_t bf_dmacontext;
|
||||
struct ath_wiphy *aphy;
|
||||
};
|
||||
|
||||
struct ath_atx_tid {
|
||||
|
|
|
@ -257,14 +257,17 @@ static const struct file_operations fops_interrupt = {
|
|||
|
||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||
int final_ts_idx, idx;
|
||||
int final_ts_idx = 0, idx, i;
|
||||
struct ath_rc_stats *stats;
|
||||
|
||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
if (!rates[i].count)
|
||||
break;
|
||||
|
||||
final_ts_idx = i;
|
||||
}
|
||||
idx = rates[final_ts_idx].idx;
|
||||
stats = &sc->debug.stats.rcstats[idx];
|
||||
stats->success++;
|
||||
|
|
|
@ -390,8 +390,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
|||
ah->config.cck_trig_high = 200;
|
||||
ah->config.cck_trig_low = 100;
|
||||
ah->config.enable_ani = 1;
|
||||
ah->config.diversity_control = ATH9K_ANT_VARIABLE;
|
||||
ah->config.antenna_switch_swap = 0;
|
||||
|
||||
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
||||
ah->config.spurchans[i][0] = AR_NO_SPUR;
|
||||
|
@ -446,9 +444,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
|||
ah->acktimeout = (u32) -1;
|
||||
ah->ctstimeout = (u32) -1;
|
||||
ah->globaltxtimeout = (u32) -1;
|
||||
|
||||
ah->gbeacon_rate = 0;
|
||||
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
}
|
||||
|
||||
|
@ -1151,7 +1146,7 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
|
|||
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
|
||||
AR_PHY_SWAP_ALT_CHAIN);
|
||||
case 0x3:
|
||||
if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) {
|
||||
if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
|
||||
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
|
||||
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
|
||||
break;
|
||||
|
@ -2056,9 +2051,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
ah->ath9k_hw_spur_mitigate_freq(ah, chan);
|
||||
ah->eep_ops->set_board_values(ah, chan);
|
||||
|
||||
if (AR_SREV_5416(ah))
|
||||
ath9k_hw_decrease_chain_power(ah, chan);
|
||||
|
||||
REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
|
||||
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
|
||||
| macStaId1
|
||||
|
@ -3518,51 +3510,6 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
|
|||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_setantenna);
|
||||
|
||||
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
|
||||
enum ath9k_ant_setting settings,
|
||||
struct ath9k_channel *chan,
|
||||
u8 *tx_chainmask,
|
||||
u8 *rx_chainmask,
|
||||
u8 *antenna_cfgd)
|
||||
{
|
||||
static u8 tx_chainmask_cfg, rx_chainmask_cfg;
|
||||
|
||||
if (AR_SREV_9280(ah)) {
|
||||
if (!tx_chainmask_cfg) {
|
||||
|
||||
tx_chainmask_cfg = *tx_chainmask;
|
||||
rx_chainmask_cfg = *rx_chainmask;
|
||||
}
|
||||
|
||||
switch (settings) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
*tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
|
||||
*rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
if (ah->caps.tx_chainmask >
|
||||
ATH9K_ANTENNA1_CHAINMASK) {
|
||||
*tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
|
||||
}
|
||||
*rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
*tx_chainmask = tx_chainmask_cfg;
|
||||
*rx_chainmask = rx_chainmask_cfg;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ah->config.diversity_control = settings;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************/
|
||||
/* General Operation */
|
||||
/*********************/
|
||||
|
|
|
@ -148,21 +148,6 @@ enum wireless_mode {
|
|||
ATH9K_MODE_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* ath9k_ant_setting - transmit antenna settings
|
||||
*
|
||||
* Configures the antenna setting to use for transmit.
|
||||
*
|
||||
* @ATH9K_ANT_VARIABLE: this means transmit on all active antennas
|
||||
* @ATH9K_ANT_FIXED_A: this means transmit on the first antenna only
|
||||
* @ATH9K_ANT_FIXED_B: this means transmit on the second antenna only
|
||||
*/
|
||||
enum ath9k_ant_setting {
|
||||
ATH9K_ANT_VARIABLE = 0,
|
||||
ATH9K_ANT_FIXED_A,
|
||||
ATH9K_ANT_FIXED_B
|
||||
};
|
||||
|
||||
enum ath9k_hw_caps {
|
||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
||||
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
||||
|
@ -226,8 +211,6 @@ struct ath9k_ops_config {
|
|||
u32 cck_trig_high;
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
enum ath9k_ant_setting diversity_control;
|
||||
u16 antenna_switch_swap;
|
||||
int serialize_regmode;
|
||||
bool intr_mitigation;
|
||||
#define SPUR_DISABLE 0
|
||||
|
@ -572,7 +555,6 @@ struct ath_hw {
|
|||
u32 acktimeout;
|
||||
u32 ctstimeout;
|
||||
u32 globaltxtimeout;
|
||||
u8 gbeacon_rate;
|
||||
|
||||
/* ANI */
|
||||
u32 proc_phyerr;
|
||||
|
@ -659,11 +641,6 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
|
|||
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
|
||||
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
|
||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
||||
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
|
||||
enum ath9k_ant_setting settings,
|
||||
struct ath9k_channel *chan,
|
||||
u8 *tx_chainmask, u8 *rx_chainmask,
|
||||
u8 *antenna_cfgd);
|
||||
|
||||
/* General Operation */
|
||||
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
||||
|
|
|
@ -1893,6 +1893,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
|
@ -2956,90 +2958,62 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
u32 rfilt = 0;
|
||||
int error, i;
|
||||
int error;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
/*
|
||||
* TODO: Need to decide which hw opmode to use for
|
||||
* multi-interface cases
|
||||
* XXX: This belongs into add_interface!
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP &&
|
||||
ah->opmode != NL80211_IFTYPE_AP) {
|
||||
ah->opmode = NL80211_IFTYPE_STATION;
|
||||
ath9k_hw_setopmode(ah);
|
||||
memcpy(common->curbssid, common->macaddr, ETH_ALEN);
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
/* Set BSSID */
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
common->curaid = 0;
|
||||
ath9k_hw_write_associd(ah);
|
||||
/* Request full reset to get hw opmode changed properly */
|
||||
sc->sc_flags |= SC_OP_FULL_RESET;
|
||||
|
||||
/* Set aggregation protection mode parameters */
|
||||
sc->config.ath_aggr_prot = 0;
|
||||
|
||||
/* Only legacy IBSS for now */
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
ath_update_chainmask(sc, 0);
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"BSSID: %pM aid: 0x%x\n",
|
||||
common->curbssid, common->curaid);
|
||||
|
||||
/* need to reconfigure the beacon */
|
||||
sc->sc_flags &= ~SC_OP_BEACONS ;
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BSSID) &&
|
||||
!is_zero_ether_addr(bss_conf->bssid)) {
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
/* Set BSSID */
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
common->curaid = 0;
|
||||
ath9k_hw_write_associd(ah);
|
||||
|
||||
/* Set aggregation protection mode parameters */
|
||||
sc->config.ath_aggr_prot = 0;
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"RX filter 0x%x bssid %pM aid 0x%x\n",
|
||||
rfilt, common->curbssid, common->curaid);
|
||||
|
||||
/* need to reconfigure the beacon */
|
||||
sc->sc_flags &= ~SC_OP_BEACONS ;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Enable transmission of beacons (AP, IBSS, MESH) */
|
||||
if ((changed & BSS_CHANGED_BEACON) ||
|
||||
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_ADHOC) ||
|
||||
(vif->type == NL80211_IFTYPE_AP) ||
|
||||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
|
||||
if ((changed & BSS_CHANGED_BEACON) ||
|
||||
(changed & BSS_CHANGED_BEACON_ENABLED &&
|
||||
bss_conf->enable_beacon)) {
|
||||
/*
|
||||
* Allocate and setup the beacon frame.
|
||||
*
|
||||
* Stop any previous beacon DMA. This may be
|
||||
* necessary, for example, when an ibss merge
|
||||
* causes reconfiguration; we may be called
|
||||
* with beacon transmission active.
|
||||
*/
|
||||
/* Disable transmission of beacons */
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
sc->beacon_interval = bss_conf->beacon_int;
|
||||
/*
|
||||
* In case of AP mode, the HW TSF has to be reset
|
||||
* when the beacon interval changes.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
} else {
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for WLAN_CAPABILITY_PRIVACY ? */
|
||||
if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
|
||||
for (i = 0; i < IEEE80211_WEP_NKID; i++)
|
||||
if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
|
||||
ath9k_hw_keysetmac(sc->sc_ah,
|
||||
(u16)i,
|
||||
common->curbssid);
|
||||
}
|
||||
|
||||
/* Only legacy IBSS for now */
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
ath_update_chainmask(sc, 0);
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
|
||||
bss_conf->use_short_preamble);
|
||||
|
@ -3065,18 +3039,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
ath9k_bss_assoc_info(sc, vif, bss_conf);
|
||||
}
|
||||
|
||||
/*
|
||||
* The HW TSF has to be reset when the beacon interval changes.
|
||||
* We set the flag here, and ath_beacon_config_ap() would take this
|
||||
* into account when it gets called through the subsequent
|
||||
* config_interface() call - with IFCC_BEACON in the changed field.
|
||||
*/
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
sc->beacon_interval = bss_conf->beacon_int;
|
||||
}
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
|
@ -3118,6 +3080,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
|
@ -3135,11 +3098,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
|||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
ath_tx_aggr_stop(sc, sta, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
ath_tx_aggr_resume(sc, sta, tid);
|
||||
|
|
|
@ -527,95 +527,6 @@ static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
|
|||
REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath9k_hw_decrease_chain_power()
|
||||
*
|
||||
* @ah: atheros hardware structure
|
||||
* @chan:
|
||||
*
|
||||
* Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios.
|
||||
*
|
||||
* Sets a chain internal RF path to the lowest output power. Any
|
||||
* further writes to bank6 after this setting will override these
|
||||
* changes. Thus this function must be the last function in the
|
||||
* sequence to modify bank 6.
|
||||
*
|
||||
* This function must be called after ar5416SetRfRegs() which is
|
||||
* called from ath9k_hw_process_ini() due to swizzling of bank 6.
|
||||
* Depends on ah->analogBank6Data being initialized by
|
||||
* ath9k_hw_set_rf_regs()
|
||||
*
|
||||
* Additional additive reduction in power -
|
||||
* change chain's switch table so chain's tx state is actually the rx
|
||||
* state value. May produce different results in 2GHz/5GHz as well as
|
||||
* board to board but in general should be a reduction.
|
||||
*
|
||||
* Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be
|
||||
* called after ah->eep_ops->set_board_values() due to RMW of
|
||||
* PHY_SWITCH_CHAIN_0.
|
||||
*/
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
int i, regWrites = 0;
|
||||
u32 bank6SelMask;
|
||||
u32 *bank6Temp = ah->bank6Temp;
|
||||
|
||||
BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
|
||||
|
||||
switch (ah->config.diversity_control) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
bank6SelMask =
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */
|
||||
REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
bank6SelMask =
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */
|
||||
REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
return; /* do not change anything */
|
||||
break;
|
||||
default:
|
||||
return; /* do not change anything */
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ah->iniBank6.ia_rows; i++)
|
||||
bank6Temp[i] = ah->analogBank6Data[i];
|
||||
|
||||
/* Write Bank 5 to switch Bank 6 write to selected chain only */
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
|
||||
|
||||
/*
|
||||
* Modify Bank6 selected chain to use lowest amplification.
|
||||
* Modifies the parameters to a value of 1.
|
||||
* Depends on existing bank 6 values to be cached in
|
||||
* ah->analogBank6Data
|
||||
*/
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
|
||||
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
|
||||
#ifdef ALTER_SWITCH
|
||||
REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
|
||||
(REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
|
||||
| ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
|
||||
* @ah: atheros hardware stucture
|
||||
|
@ -687,7 +598,6 @@ int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
}
|
||||
|
||||
ath9k_hw_force_bias(ah, freq);
|
||||
ath9k_hw_decrease_chain_power(ah, chan);
|
||||
|
||||
reg32 =
|
||||
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
|
||||
|
|
|
@ -35,9 +35,6 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
|
|||
struct ath9k_channel *chan,
|
||||
u16 modesIndex);
|
||||
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
|
||||
#define AR_PHY_BASE 0x9800
|
||||
#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
|
||||
|
||||
|
|
|
@ -859,12 +859,12 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|||
static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
const struct ath_rate_table *rate_table,
|
||||
struct ath_rate_priv *ath_rc_priv,
|
||||
struct ath_tx_info_priv *tx_info_priv,
|
||||
struct ieee80211_tx_info *tx_info,
|
||||
int tx_rate, int xretries, int retries,
|
||||
u32 now_msec)
|
||||
{
|
||||
bool state_change = false;
|
||||
int count;
|
||||
int count, n_bad_frames;
|
||||
u8 last_per;
|
||||
static u32 nretry_to_per_lookup[10] = {
|
||||
100 * 0 / 1,
|
||||
|
@ -880,6 +880,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
|||
};
|
||||
|
||||
last_per = ath_rc_priv->per[tx_rate];
|
||||
n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len;
|
||||
|
||||
if (xretries) {
|
||||
if (xretries == 1) {
|
||||
|
@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
|||
if (retries >= count)
|
||||
retries = count - 1;
|
||||
|
||||
if (tx_info_priv->n_bad_frames) {
|
||||
if (n_bad_frames) {
|
||||
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
|
||||
* Assuming that n_frames is not 0. The current PER
|
||||
* from the retries is 100 * retries / (retries+1),
|
||||
|
@ -920,14 +921,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
|||
* the above PER. The expression below is a
|
||||
* simplified version of the sum of these two terms.
|
||||
*/
|
||||
if (tx_info_priv->n_frames > 0) {
|
||||
int n_frames, n_bad_frames;
|
||||
if (tx_info->status.ampdu_len > 0) {
|
||||
int n_frames, n_bad_tries;
|
||||
u8 cur_per, new_per;
|
||||
|
||||
n_bad_frames = retries * tx_info_priv->n_frames +
|
||||
tx_info_priv->n_bad_frames;
|
||||
n_frames = tx_info_priv->n_frames * (retries + 1);
|
||||
cur_per = (100 * n_bad_frames / n_frames) >> 3;
|
||||
n_bad_tries = retries * tx_info->status.ampdu_len +
|
||||
n_bad_frames;
|
||||
n_frames = tx_info->status.ampdu_len * (retries + 1);
|
||||
cur_per = (100 * n_bad_tries / n_frames) >> 3;
|
||||
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
|
||||
ath_rc_priv->per[tx_rate] = new_per;
|
||||
}
|
||||
|
@ -943,8 +944,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
|||
* this was a probe. Otherwise, ignore the probe.
|
||||
*/
|
||||
if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
|
||||
if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
|
||||
tx_info_priv->n_frames) {
|
||||
if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) {
|
||||
/*
|
||||
* Since we probed with just a single attempt,
|
||||
* any retries means the probe failed. Also,
|
||||
|
@ -1003,7 +1003,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
|||
|
||||
static void ath_rc_update_ht(struct ath_softc *sc,
|
||||
struct ath_rate_priv *ath_rc_priv,
|
||||
struct ath_tx_info_priv *tx_info_priv,
|
||||
struct ieee80211_tx_info *tx_info,
|
||||
int tx_rate, int xretries, int retries)
|
||||
{
|
||||
u32 now_msec = jiffies_to_msecs(jiffies);
|
||||
|
@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
|
|||
|
||||
/* Update PER first */
|
||||
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
|
||||
tx_info_priv, tx_rate, xretries,
|
||||
tx_info, tx_rate, xretries,
|
||||
retries, now_msec);
|
||||
|
||||
/*
|
||||
|
@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
|||
struct ieee80211_tx_info *tx_info,
|
||||
int final_ts_idx, int xretries, int long_retry)
|
||||
{
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
const struct ath_rate_table *rate_table;
|
||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||
u8 flags;
|
||||
|
@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
|||
return;
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
ath_rc_update_ht(sc, ath_rc_priv,
|
||||
tx_info_priv, rix,
|
||||
xretries ? 1 : 2,
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info,
|
||||
rix, xretries ? 1 : 2,
|
||||
rates[i].count);
|
||||
}
|
||||
}
|
||||
|
@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
|||
return;
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
|
||||
xretries, long_retry);
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
|
||||
}
|
||||
|
||||
static const
|
||||
|
@ -1301,23 +1298,30 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
{
|
||||
struct ath_softc *sc = priv;
|
||||
struct ath_rate_priv *ath_rc_priv = priv_sta;
|
||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
int final_ts_idx, tx_status = 0, is_underrun = 0;
|
||||
int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
|
||||
int long_retry = 0;
|
||||
__le16 fc;
|
||||
int i;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = hdr->frame_control;
|
||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
|
||||
if (!rate->count)
|
||||
break;
|
||||
|
||||
final_ts_idx = i;
|
||||
long_retry = rate->count - 1;
|
||||
}
|
||||
|
||||
if (!priv_sta || !ieee80211_is_data(fc) ||
|
||||
!tx_info_priv->update_rc)
|
||||
goto exit;
|
||||
!(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC))
|
||||
return;
|
||||
|
||||
if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
|
||||
goto exit;
|
||||
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If underrun error is seen assume it as an excessive retry only
|
||||
|
@ -1325,20 +1329,17 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
* Adjust the long retry as if the frame was tried hw->max_rate_tries
|
||||
* times. This affects how ratectrl updates PER for the failed rate.
|
||||
*/
|
||||
if (tx_info_priv->tx.ts_flags &
|
||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
|
||||
((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
|
||||
if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
|
||||
(sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
|
||||
tx_status = 1;
|
||||
is_underrun = 1;
|
||||
}
|
||||
|
||||
if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
|
||||
(tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
|
||||
if (tx_info->pad[0] & ATH_TX_INFO_XRETRY)
|
||||
tx_status = 1;
|
||||
|
||||
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
|
||||
(is_underrun) ? sc->hw->max_rate_tries :
|
||||
tx_info_priv->tx.ts_longretry);
|
||||
(is_underrun) ? sc->hw->max_rate_tries : long_retry);
|
||||
|
||||
/* Check if aggregation has to be enabled for this tid */
|
||||
if (conf_is_ht(&sc->hw->conf) &&
|
||||
|
@ -1352,13 +1353,11 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
if(ath_tx_aggr_check(sc, an, tid))
|
||||
ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid);
|
||||
ieee80211_start_tx_ba_session(sta, tid);
|
||||
}
|
||||
}
|
||||
|
||||
ath_debug_stat_rc(sc, skb);
|
||||
exit:
|
||||
kfree(tx_info_priv);
|
||||
}
|
||||
|
||||
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
||||
|
|
|
@ -167,24 +167,18 @@ struct ath_rate_priv {
|
|||
struct ath_rate_softc *asc;
|
||||
};
|
||||
|
||||
#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0)
|
||||
#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1)
|
||||
#define ATH_TX_INFO_UPDATE_RC (1 << 2)
|
||||
#define ATH_TX_INFO_XRETRY (1 << 3)
|
||||
#define ATH_TX_INFO_UNDERRUN (1 << 4)
|
||||
|
||||
enum ath9k_internal_frame_type {
|
||||
ATH9K_NOT_INTERNAL,
|
||||
ATH9K_INT_PAUSE,
|
||||
ATH9K_INT_UNPAUSE
|
||||
};
|
||||
|
||||
struct ath_tx_info_priv {
|
||||
struct ath_wiphy *aphy;
|
||||
struct ath_tx_status tx;
|
||||
int n_frames;
|
||||
int n_bad_frames;
|
||||
bool update_rc;
|
||||
enum ath9k_internal_frame_type frame_type;
|
||||
};
|
||||
|
||||
#define ATH_TX_INFO_PRIV(tx_info) \
|
||||
((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
|
||||
|
||||
void ath_rate_attach(struct ath_softc *sc);
|
||||
u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
|
||||
int ath_rate_control_register(void);
|
||||
|
|
|
@ -338,13 +338,11 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
|
|||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
|
||||
if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
|
||||
if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) &&
|
||||
aphy->state == ATH_WIPHY_PAUSING) {
|
||||
if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
|
||||
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
|
||||
printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
|
||||
"frame\n", wiphy_name(hw->wiphy));
|
||||
/*
|
||||
|
@ -363,9 +361,6 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
|
|||
|
||||
ATH_TXBUF_RESET(tbf);
|
||||
|
||||
tbf->aphy = bf->aphy;
|
||||
tbf->bf_mpdu = bf->bf_mpdu;
|
||||
tbf->bf_buf_addr = bf->bf_buf_addr;
|
||||
*(tbf->bf_desc) = *(bf->bf_desc);
|
||||
|
@ -270,7 +271,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
struct ath_atx_tid *tid = NULL;
|
||||
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
|
||||
struct ath_desc *ds = bf_last->bf_desc;
|
||||
|
@ -284,8 +284,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
|
||||
hw = tx_info_priv->aphy->hw;
|
||||
hw = bf->aphy->hw;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
@ -464,7 +463,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ieee80211_tx_rate *rates;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
u32 max_4ms_framelen, frmlen;
|
||||
u16 aggr_limit, legacy = 0;
|
||||
int i;
|
||||
|
@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
skb = bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
|
||||
|
||||
/*
|
||||
* Find the lowest frame length among the rate series that will have a
|
||||
|
@ -702,7 +699,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|||
/* anchor last desc of aggregate */
|
||||
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
|
||||
|
||||
txq->axq_aggr_depth++;
|
||||
ath_tx_txqaddbuf(sc, txq, &bf_q);
|
||||
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
||||
|
||||
|
@ -878,8 +874,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
|||
INIT_LIST_HEAD(&txq->axq_acq);
|
||||
spin_lock_init(&txq->axq_lock);
|
||||
txq->axq_depth = 0;
|
||||
txq->axq_aggr_depth = 0;
|
||||
txq->axq_linkbuf = NULL;
|
||||
txq->axq_tx_inprogress = false;
|
||||
sc->tx.txqsetup |= 1<<qnum;
|
||||
}
|
||||
|
@ -1014,7 +1008,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
|||
|
||||
if (list_empty(&txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
txq->axq_linkbuf = NULL;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
|
@ -1199,7 +1192,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
|||
|
||||
list_splice_tail_init(head, &txq->axq_q);
|
||||
txq->axq_depth++;
|
||||
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
|
||||
|
||||
ath_print(common, ATH_DBG_QUEUE,
|
||||
"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
|
||||
|
@ -1560,21 +1552,26 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
|||
struct ath_softc *sc = aphy->sc;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
int hdrlen;
|
||||
__le16 fc;
|
||||
|
||||
tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
|
||||
if (unlikely(!tx_info_priv))
|
||||
return -ENOMEM;
|
||||
tx_info->rate_driver_data[0] = tx_info_priv;
|
||||
tx_info_priv->aphy = aphy;
|
||||
tx_info_priv->frame_type = txctl->frame_type;
|
||||
tx_info->pad[0] = 0;
|
||||
switch (txctl->frame_type) {
|
||||
case ATH9K_NOT_INTERNAL:
|
||||
break;
|
||||
case ATH9K_INT_PAUSE:
|
||||
tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
|
||||
/* fall through */
|
||||
case ATH9K_INT_UNPAUSE:
|
||||
tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
|
||||
break;
|
||||
}
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
fc = hdr->frame_control;
|
||||
|
||||
ATH_TXBUF_RESET(bf);
|
||||
|
||||
bf->aphy = aphy;
|
||||
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
|
||||
|
||||
if (conf_is_ht(&hw->conf) && !is_pae(skb))
|
||||
|
@ -1599,8 +1596,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
|||
skb->len, DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
|
||||
bf->bf_mpdu = NULL;
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
|
||||
"dma_mapping_error() on TX\n");
|
||||
return -ENOMEM;
|
||||
|
@ -1781,27 +1776,17 @@ exit:
|
|||
/*****************/
|
||||
|
||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
int tx_flags)
|
||||
struct ath_wiphy *aphy, int tx_flags)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int hdrlen, padsize;
|
||||
int frame_type = ATH9K_NOT_INTERNAL;
|
||||
|
||||
ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
|
||||
|
||||
if (tx_info_priv) {
|
||||
hw = tx_info_priv->aphy->hw;
|
||||
frame_type = tx_info_priv->frame_type;
|
||||
}
|
||||
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
|
||||
tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
}
|
||||
if (aphy)
|
||||
hw = aphy->hw;
|
||||
|
||||
if (tx_flags & ATH_TX_BAR)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
|
@ -1833,10 +1818,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
SC_OP_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
|
||||
if (frame_type == ATH9K_NOT_INTERNAL)
|
||||
ieee80211_tx_status(hw, skb);
|
||||
else
|
||||
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
|
||||
ath9k_tx_status(hw, skb);
|
||||
else
|
||||
ieee80211_tx_status(hw, skb);
|
||||
}
|
||||
|
||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
|
@ -1859,7 +1844,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
|||
}
|
||||
|
||||
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
|
||||
ath_tx_complete(sc, skb, tx_flags);
|
||||
ath_tx_complete(sc, skb, bf->aphy, tx_flags);
|
||||
ath_debug_stat_tx(sc, txq, bf);
|
||||
|
||||
/*
|
||||
|
@ -1907,8 +1892,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
|
|||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
|
||||
struct ieee80211_hw *hw = bf->aphy->hw;
|
||||
u8 i, tx_rateindex;
|
||||
|
||||
if (txok)
|
||||
|
@ -1917,17 +1901,22 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
|
|||
tx_rateindex = ds->ds_txstat.ts_rateindex;
|
||||
WARN_ON(tx_rateindex >= hw->max_rates);
|
||||
|
||||
tx_info_priv->update_rc = update_rc;
|
||||
if (update_rc)
|
||||
tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;
|
||||
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
||||
|
||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
||||
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
memcpy(&tx_info_priv->tx, &ds->ds_txstat,
|
||||
sizeof(tx_info_priv->tx));
|
||||
tx_info_priv->n_frames = bf->bf_nframes;
|
||||
tx_info_priv->n_bad_frames = nbad;
|
||||
if (ds->ds_txstat.ts_flags &
|
||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
|
||||
tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
|
||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
|
||||
(ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
|
||||
tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
|
||||
tx_info->status.ampdu_len = bf->bf_nframes;
|
||||
tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1971,7 +1960,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
spin_lock_bh(&txq->axq_lock);
|
||||
if (list_empty(&txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
txq->axq_linkbuf = NULL;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
|
@ -2005,10 +1993,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
if (bf->bf_desc == txq->axq_lastdsWithCTS)
|
||||
txq->axq_lastdsWithCTS = NULL;
|
||||
if (ds == txq->axq_gatingds)
|
||||
txq->axq_gatingds = NULL;
|
||||
|
||||
/*
|
||||
* Remove ath_buf's of the same transmit unit from txq,
|
||||
|
@ -2022,9 +2006,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
|||
&txq->axq_q, lastbf->list.prev);
|
||||
|
||||
txq->axq_depth--;
|
||||
if (bf_isaggr(bf))
|
||||
txq->axq_aggr_depth--;
|
||||
|
||||
txok = (ds->ds_txstat.ts_status == 0);
|
||||
txq->axq_tx_inprogress = false;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
|
|
@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
|||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
wiphy->reg_notifier = reg_notifier;
|
||||
wiphy->strict_regulatory = true;
|
||||
wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||
|
||||
if (ath_is_world_regd(reg)) {
|
||||
/*
|
||||
|
@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
|||
* saved on the wiphy orig_* parameters
|
||||
*/
|
||||
regd = ath_world_regdomain(reg);
|
||||
wiphy->custom_regulatory = true;
|
||||
wiphy->strict_regulatory = false;
|
||||
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
} else {
|
||||
/*
|
||||
* This gets applied in the case of the absense of CRDA,
|
||||
|
|
|
@ -383,44 +383,160 @@ static inline
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if a DMA region fits the device constraints.
|
||||
* Returns true, if the region is OK for usage with this device. */
|
||||
static inline bool b43_dma_address_ok(struct b43_dmaring *ring,
|
||||
dma_addr_t addr, size_t size)
|
||||
{
|
||||
switch (ring->type) {
|
||||
case B43_DMA_30BIT:
|
||||
if ((u64)addr + size > (1ULL << 30))
|
||||
return 0;
|
||||
break;
|
||||
case B43_DMA_32BIT:
|
||||
if ((u64)addr + size > (1ULL << 32))
|
||||
return 0;
|
||||
break;
|
||||
case B43_DMA_64BIT:
|
||||
/* Currently we can't have addresses beyond
|
||||
* 64bit in the kernel. */
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define is_4k_aligned(addr) (((u64)(addr) & 0x0FFFull) == 0)
|
||||
#define is_8k_aligned(addr) (((u64)(addr) & 0x1FFFull) == 0)
|
||||
|
||||
static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base,
|
||||
dma_addr_t dmaaddr, size_t size)
|
||||
{
|
||||
ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE);
|
||||
free_pages((unsigned long)base, get_order(size));
|
||||
}
|
||||
|
||||
static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring,
|
||||
dma_addr_t *dmaaddr, size_t size,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = (void *)__get_free_pages(gfp_flags, get_order(size));
|
||||
if (!base)
|
||||
return NULL;
|
||||
memset(base, 0, size);
|
||||
*dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size,
|
||||
DMA_TO_DEVICE);
|
||||
if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) {
|
||||
free_pages((unsigned long)base, get_order(size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static void * b43_get_and_map_ringmem(struct b43_dmaring *ring,
|
||||
dma_addr_t *dmaaddr, size_t size)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
|
||||
GFP_KERNEL);
|
||||
if (!base) {
|
||||
b43err(ring->dev->wl, "Failed to allocate or map pages "
|
||||
"for DMA ringmemory\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
|
||||
/* The memory does not fit our device constraints.
|
||||
* Retry with GFP_DMA set to get lower memory. */
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!base) {
|
||||
b43err(ring->dev->wl, "Failed to allocate or map pages "
|
||||
"in the GFP_DMA region for DMA ringmemory\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
b43err(ring->dev->wl, "Failed to allocate DMA "
|
||||
"ringmemory that fits device constraints\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* We expect the memory to be 4k aligned, at least. */
|
||||
if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) {
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static int alloc_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
unsigned int required;
|
||||
void *base;
|
||||
dma_addr_t dmaaddr;
|
||||
|
||||
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
|
||||
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
|
||||
* has shown that 4K is sufficient for the latter as long as the buffer
|
||||
* does not cross an 8K boundary.
|
||||
*
|
||||
* For unknown reasons - possibly a hardware error - the BCM4311 rev
|
||||
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
|
||||
* which accounts for the GFP_DMA flag below.
|
||||
*
|
||||
* The flags here must match the flags in free_ringmemory below!
|
||||
/* There are several requirements to the descriptor ring memory:
|
||||
* - The memory region needs to fit the address constraints for the
|
||||
* device (same as for frame buffers).
|
||||
* - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
|
||||
* - For 64bit DMA devices, the descriptor ring must be 8k aligned.
|
||||
*/
|
||||
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
|
||||
B43_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), flags);
|
||||
if (!ring->descbase) {
|
||||
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
|
||||
required = ring->nr_slots * sizeof(struct b43_dmadesc64);
|
||||
else
|
||||
required = ring->nr_slots * sizeof(struct b43_dmadesc32);
|
||||
if (B43_WARN_ON(required > 0x1000))
|
||||
return -ENOMEM;
|
||||
|
||||
ring->alloc_descsize = 0x1000;
|
||||
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
ring->alloc_descbase = base;
|
||||
ring->alloc_dmabase = dmaaddr;
|
||||
|
||||
if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) {
|
||||
/* We're on <=32bit DMA, or we already got 8k aligned memory.
|
||||
* That's all we need, so we're fine. */
|
||||
ring->descbase = base;
|
||||
ring->dmabase = dmaaddr;
|
||||
return 0;
|
||||
}
|
||||
memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
|
||||
b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize);
|
||||
|
||||
/* Ok, we failed at the 8k alignment requirement.
|
||||
* Try to force-align the memory region now. */
|
||||
ring->alloc_descsize = 0x2000;
|
||||
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
ring->alloc_descbase = base;
|
||||
ring->alloc_dmabase = dmaaddr;
|
||||
|
||||
if (is_8k_aligned(dmaaddr)) {
|
||||
/* We're already 8k aligned. That Ok, too. */
|
||||
ring->descbase = base;
|
||||
ring->dmabase = dmaaddr;
|
||||
return 0;
|
||||
}
|
||||
/* Force-align it to 8k */
|
||||
ring->descbase = (void *)((u8 *)base + 0x1000);
|
||||
ring->dmabase = dmaaddr + 0x1000;
|
||||
B43_WARN_ON(!is_8k_aligned(ring->dmabase));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
|
||||
ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase, flags);
|
||||
b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
|
||||
ring->alloc_dmabase, ring->alloc_descsize);
|
||||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
|
@ -530,29 +646,14 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
|
|||
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
|
||||
return 1;
|
||||
|
||||
switch (ring->type) {
|
||||
case B43_DMA_30BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 30))
|
||||
goto address_error;
|
||||
break;
|
||||
case B43_DMA_32BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 32))
|
||||
goto address_error;
|
||||
break;
|
||||
case B43_DMA_64BIT:
|
||||
/* Currently we can't have addresses beyond
|
||||
* 64bit in the kernel. */
|
||||
break;
|
||||
if (!b43_dma_address_ok(ring, addr, buffersize)) {
|
||||
/* We can't support this address. Unmap it again. */
|
||||
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The address is OK. */
|
||||
return 0;
|
||||
|
||||
address_error:
|
||||
/* We can't support this address. Unmap it again. */
|
||||
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
|
||||
|
@ -614,6 +715,9 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
|||
meta->dmaaddr = dmaaddr;
|
||||
ring->ops->fill_descriptor(ring, desc, dmaaddr,
|
||||
ring->rx_buffersize, 0, 0, 0);
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
ring->alloc_dmabase,
|
||||
ring->alloc_descsize, DMA_TO_DEVICE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -770,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
|
|||
for (i = 0; i < ring->nr_slots; i++) {
|
||||
desc = ring->ops->idx2desc(ring, i, &meta);
|
||||
|
||||
if (!meta->skb) {
|
||||
if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) {
|
||||
B43_WARN_ON(!ring->tx);
|
||||
continue;
|
||||
}
|
||||
|
@ -822,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
enum b43_dmatype type)
|
||||
{
|
||||
struct b43_dmaring *ring;
|
||||
int err;
|
||||
int i, err;
|
||||
dma_addr_t dma_test;
|
||||
|
||||
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
||||
|
@ -837,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
|||
GFP_KERNEL);
|
||||
if (!ring->meta)
|
||||
goto err_kfree_ring;
|
||||
for (i = 0; i < ring->nr_slots; i++)
|
||||
ring->meta->skb = B43_DMA_PTR_POISON;
|
||||
|
||||
ring->type = type;
|
||||
ring->dev = dev;
|
||||
|
@ -1147,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
|
|||
case 0x5000:
|
||||
ring = dma->tx_ring_mcast;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
*slot = (cookie & 0x0FFF);
|
||||
B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
|
||||
if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) {
|
||||
b43dbg(dev->wl, "TX-status contains "
|
||||
"invalid cookie: 0x%04X\n", cookie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
@ -1246,6 +1354,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
|||
}
|
||||
/* Now transfer the whole frame. */
|
||||
wmb();
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
ring->alloc_dmabase,
|
||||
ring->alloc_descsize, DMA_TO_DEVICE);
|
||||
ops->poke_tx(ring, next_slot(ring, slot));
|
||||
return 0;
|
||||
|
||||
|
@ -1387,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
|||
struct b43_dmaring *ring;
|
||||
struct b43_dmadesc_generic *desc;
|
||||
struct b43_dmadesc_meta *meta;
|
||||
int slot;
|
||||
int slot, firstused;
|
||||
bool frame_succeed;
|
||||
|
||||
ring = parse_cookie(dev, status->cookie, &slot);
|
||||
if (unlikely(!ring))
|
||||
return;
|
||||
|
||||
B43_WARN_ON(!ring->tx);
|
||||
|
||||
/* Sanity check: TX packets are processed in-order on one ring.
|
||||
* Check if the slot deduced from the cookie really is the first
|
||||
* used slot. */
|
||||
firstused = ring->current_slot - ring->used_slots + 1;
|
||||
if (firstused < 0)
|
||||
firstused = ring->nr_slots + firstused;
|
||||
if (unlikely(slot != firstused)) {
|
||||
/* This possibly is a firmware bug and will result in
|
||||
* malfunction, memory leaks and/or stall of DMA functionality. */
|
||||
b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
|
||||
"Expected %d, but got %d\n",
|
||||
ring->index, firstused, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
ops = ring->ops;
|
||||
while (1) {
|
||||
B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
|
||||
B43_WARN_ON(slot < 0 || slot >= ring->nr_slots);
|
||||
desc = ops->idx2desc(ring, slot, &meta);
|
||||
|
||||
if (b43_dma_ptr_is_poisoned(meta->skb)) {
|
||||
b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) "
|
||||
"on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
if (meta->skb) {
|
||||
struct b43_private_tx_info *priv_info =
|
||||
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
|
||||
|
@ -1415,7 +1547,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
|||
if (meta->is_last_fragment) {
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
BUG_ON(!meta->skb);
|
||||
if (unlikely(!meta->skb)) {
|
||||
/* This is a scatter-gather fragment of a frame, so
|
||||
* the skb pointer must not be NULL. */
|
||||
b43dbg(dev->wl, "TX status unexpected NULL skb "
|
||||
"at slot %d (first=%d) on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(meta->skb);
|
||||
|
||||
|
@ -1433,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
|||
#endif /* DEBUG */
|
||||
ieee80211_tx_status(dev->wl->hw, meta->skb);
|
||||
|
||||
/* skb is freed by ieee80211_tx_status() */
|
||||
meta->skb = NULL;
|
||||
/* skb will be freed by ieee80211_tx_status().
|
||||
* Poison our pointer. */
|
||||
meta->skb = B43_DMA_PTR_POISON;
|
||||
} else {
|
||||
/* No need to call free_descriptor_buffer here, as
|
||||
* this is only the txhdr, which is not allocated.
|
||||
*/
|
||||
B43_WARN_ON(meta->skb);
|
||||
if (unlikely(meta->skb)) {
|
||||
b43dbg(dev->wl, "TX status unexpected non-NULL skb "
|
||||
"at slot %d (first=%d) on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Everything unmapped and free'd. So it's not used anymore. */
|
||||
ring->used_slots--;
|
||||
|
||||
if (meta->is_last_fragment)
|
||||
if (meta->is_last_fragment) {
|
||||
/* This is the last scatter-gather
|
||||
* fragment of the frame. We are done. */
|
||||
break;
|
||||
}
|
||||
slot = next_slot(ring, slot);
|
||||
}
|
||||
if (ring->stopped) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef B43_DMA_H_
|
||||
#define B43_DMA_H_
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "b43.h"
|
||||
|
||||
|
@ -157,7 +157,6 @@ struct b43_dmadesc_generic {
|
|||
} __attribute__ ((__packed__));
|
||||
|
||||
/* Misc DMA constants */
|
||||
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
|
||||
#define B43_DMA0_RX_FRAMEOFFSET 30
|
||||
|
||||
/* DMA engine tuning knobs */
|
||||
|
@ -165,6 +164,10 @@ struct b43_dmadesc_generic {
|
|||
#define B43_RXRING_SLOTS 64
|
||||
#define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN
|
||||
|
||||
/* Pointer poison */
|
||||
#define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM))
|
||||
#define b43_dma_ptr_is_poisoned(ptr) (unlikely((ptr) == B43_DMA_PTR_POISON))
|
||||
|
||||
|
||||
struct sk_buff;
|
||||
struct b43_private;
|
||||
|
@ -243,6 +246,12 @@ struct b43_dmaring {
|
|||
/* The QOS priority assigned to this ring. Only used for TX rings.
|
||||
* This is the mac80211 "queue" value. */
|
||||
u8 queue_prio;
|
||||
/* Pointers and size of the originally allocated and mapped memory
|
||||
* region for the descriptor ring. */
|
||||
void *alloc_descbase;
|
||||
dma_addr_t alloc_dmabase;
|
||||
unsigned int alloc_descsize;
|
||||
/* Pointer to our wireless device. */
|
||||
struct b43_wldev *dev;
|
||||
#ifdef CONFIG_B43_DEBUG
|
||||
/* Maximum number of used slots. */
|
||||
|
|
|
@ -296,6 +296,33 @@ static const char *command_types[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define WEXT_USECHANNELS 1
|
||||
|
||||
static const long ipw2100_frequencies[] = {
|
||||
2412, 2417, 2422, 2427,
|
||||
2432, 2437, 2442, 2447,
|
||||
2452, 2457, 2462, 2467,
|
||||
2472, 2484
|
||||
};
|
||||
|
||||
#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
|
||||
|
||||
static const long ipw2100_rates_11b[] = {
|
||||
1000000,
|
||||
2000000,
|
||||
5500000,
|
||||
11000000
|
||||
};
|
||||
|
||||
static struct ieee80211_rate ipw2100_bg_rates[] = {
|
||||
{ .bitrate = 10 },
|
||||
{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
};
|
||||
|
||||
#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
|
||||
|
||||
/* Pre-decl until we get the code solid and then we can clean it up */
|
||||
static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
|
||||
static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
|
||||
|
@ -1141,6 +1168,7 @@ static int rf_kill_active(struct ipw2100_priv *priv)
|
|||
int i;
|
||||
|
||||
if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||
priv->status &= ~STATUS_RF_KILL_HW;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1151,10 +1179,13 @@ static int rf_kill_active(struct ipw2100_priv *priv)
|
|||
value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
if (value == 0) {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
else
|
||||
} else {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||
priv->status &= ~STATUS_RF_KILL_HW;
|
||||
}
|
||||
|
||||
return (value == 0);
|
||||
}
|
||||
|
@ -1814,13 +1845,6 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Called by register_netdev() */
|
||||
static int ipw2100_net_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
return ipw2100_up(priv, 1);
|
||||
}
|
||||
|
||||
static void ipw2100_down(struct ipw2100_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -1875,6 +1899,64 @@ static void ipw2100_down(struct ipw2100_priv *priv)
|
|||
netif_stop_queue(priv->net_dev);
|
||||
}
|
||||
|
||||
/* Called by register_netdev() */
|
||||
static int ipw2100_net_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
|
||||
struct wireless_dev *wdev = &priv->ieee->wdev;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = ipw2100_up(priv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
|
||||
|
||||
/* fill-out priv->ieee->bg_band */
|
||||
if (geo->bg_channels) {
|
||||
struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
|
||||
|
||||
bg_band->band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->n_channels = geo->bg_channels;
|
||||
bg_band->channels =
|
||||
kzalloc(geo->bg_channels *
|
||||
sizeof(struct ieee80211_channel), GFP_KERNEL);
|
||||
/* translate geo->bg to bg_band.channels */
|
||||
for (i = 0; i < geo->bg_channels; i++) {
|
||||
bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->channels[i].center_freq = geo->bg[i].freq;
|
||||
bg_band->channels[i].hw_value = geo->bg[i].channel;
|
||||
bg_band->channels[i].max_power = geo->bg[i].max_power;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_NO_IBSS;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_RADAR;
|
||||
/* No equivalent for LIBIPW_CH_80211H_RULES,
|
||||
LIBIPW_CH_UNIFORM_SPREADING, or
|
||||
LIBIPW_CH_B_ONLY... */
|
||||
}
|
||||
/* point at bitrate info */
|
||||
bg_band->bitrates = ipw2100_bg_rates;
|
||||
bg_band->n_bitrates = RATE_COUNT;
|
||||
|
||||
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
|
||||
}
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
|
||||
if (wiphy_register(wdev->wiphy)) {
|
||||
ipw2100_down(priv);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipw2100_reset_adapter(struct work_struct *work)
|
||||
{
|
||||
struct ipw2100_priv *priv =
|
||||
|
@ -2090,6 +2172,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
|
|||
priv->net_dev->name);
|
||||
|
||||
/* RF_KILL is now enabled (else we wouldn't be here) */
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
|
||||
/* Make sure the RF Kill check timer is running */
|
||||
|
@ -6029,7 +6112,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
|
|||
struct ipw2100_priv *priv;
|
||||
struct net_device *dev;
|
||||
|
||||
dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
|
||||
dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
priv = libipw_priv(dev);
|
||||
|
@ -6342,7 +6425,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
|||
sysfs_remove_group(&pci_dev->dev.kobj,
|
||||
&ipw2100_attribute_group);
|
||||
|
||||
free_ieee80211(dev);
|
||||
free_ieee80211(dev, 0);
|
||||
pci_set_drvdata(pci_dev, NULL);
|
||||
}
|
||||
|
||||
|
@ -6400,7 +6483,10 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
|
|||
if (dev->base_addr)
|
||||
iounmap((void __iomem *)dev->base_addr);
|
||||
|
||||
free_ieee80211(dev);
|
||||
/* wiphy_unregister needs to be here, before free_ieee80211 */
|
||||
wiphy_unregister(priv->ieee->wdev.wiphy);
|
||||
kfree(priv->ieee->bg_band.channels);
|
||||
free_ieee80211(dev, 0);
|
||||
}
|
||||
|
||||
pci_release_regions(pci_dev);
|
||||
|
@ -6601,26 +6687,6 @@ static void __exit ipw2100_exit(void)
|
|||
module_init(ipw2100_init);
|
||||
module_exit(ipw2100_exit);
|
||||
|
||||
#define WEXT_USECHANNELS 1
|
||||
|
||||
static const long ipw2100_frequencies[] = {
|
||||
2412, 2417, 2422, 2427,
|
||||
2432, 2437, 2442, 2447,
|
||||
2452, 2457, 2462, 2467,
|
||||
2472, 2484
|
||||
};
|
||||
|
||||
#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
|
||||
|
||||
static const long ipw2100_rates_11b[] = {
|
||||
1000000,
|
||||
2000000,
|
||||
5500000,
|
||||
11000000
|
||||
};
|
||||
|
||||
#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
|
||||
|
||||
static int ipw2100_wx_get_name(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra)
|
||||
|
|
|
@ -109,6 +109,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH;
|
|||
static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
|
||||
#endif
|
||||
|
||||
static struct ieee80211_rate ipw2200_rates[] = {
|
||||
{ .bitrate = 10 },
|
||||
{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 60 },
|
||||
{ .bitrate = 90 },
|
||||
{ .bitrate = 120 },
|
||||
{ .bitrate = 180 },
|
||||
{ .bitrate = 240 },
|
||||
{ .bitrate = 360 },
|
||||
{ .bitrate = 480 },
|
||||
{ .bitrate = 540 }
|
||||
};
|
||||
|
||||
#define ipw2200_a_rates (ipw2200_rates + 4)
|
||||
#define ipw2200_num_a_rates 8
|
||||
#define ipw2200_bg_rates (ipw2200_rates + 0)
|
||||
#define ipw2200_num_bg_rates 12
|
||||
|
||||
#ifdef CONFIG_IPW2200_QOS
|
||||
static int qos_enable = 0;
|
||||
|
@ -1739,10 +1758,13 @@ static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
|
|||
|
||||
static int rf_kill_active(struct ipw_priv *priv)
|
||||
{
|
||||
if (0 == (ipw_read32(priv, 0x30) & 0x10000))
|
||||
if (0 == (ipw_read32(priv, 0x30) & 0x10000)) {
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
else
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
} else {
|
||||
priv->status &= ~STATUS_RF_KILL_HW;
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||
}
|
||||
|
||||
return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
|
||||
}
|
||||
|
@ -2025,6 +2047,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
|
|||
if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
|
||||
IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
||||
cancel_delayed_work(&priv->request_scan);
|
||||
|
@ -8660,24 +8683,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option)
|
|||
*
|
||||
*/
|
||||
|
||||
static int ipw_wx_get_name(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra)
|
||||
{
|
||||
struct ipw_priv *priv = libipw_priv(dev);
|
||||
mutex_lock(&priv->mutex);
|
||||
if (priv->status & STATUS_RF_KILL_MASK)
|
||||
strcpy(wrqu->name, "radio off");
|
||||
else if (!(priv->status & STATUS_ASSOCIATED))
|
||||
strcpy(wrqu->name, "unassociated");
|
||||
else
|
||||
snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
|
||||
ipw_modes[priv->assoc_request.ieee_mode]);
|
||||
IPW_DEBUG_WX("Name: %s\n", wrqu->name);
|
||||
mutex_unlock(&priv->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
|
||||
{
|
||||
if (channel == 0) {
|
||||
|
@ -9977,7 +9982,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
|
|||
/* Rebase the WE IOCTLs to zero for the handler array */
|
||||
#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
|
||||
static iw_handler ipw_wx_handlers[] = {
|
||||
IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
|
||||
IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
|
||||
IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
|
||||
IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
|
||||
IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
|
||||
|
@ -11422,16 +11427,100 @@ static void ipw_bg_down(struct work_struct *work)
|
|||
/* Called by register_netdev() */
|
||||
static int ipw_net_init(struct net_device *dev)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct ipw_priv *priv = libipw_priv(dev);
|
||||
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
|
||||
struct wireless_dev *wdev = &priv->ieee->wdev;
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (ipw_up(priv)) {
|
||||
mutex_unlock(&priv->mutex);
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
|
||||
|
||||
/* fill-out priv->ieee->bg_band */
|
||||
if (geo->bg_channels) {
|
||||
struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
|
||||
|
||||
bg_band->band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->n_channels = geo->bg_channels;
|
||||
bg_band->channels =
|
||||
kzalloc(geo->bg_channels *
|
||||
sizeof(struct ieee80211_channel), GFP_KERNEL);
|
||||
/* translate geo->bg to bg_band.channels */
|
||||
for (i = 0; i < geo->bg_channels; i++) {
|
||||
bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->channels[i].center_freq = geo->bg[i].freq;
|
||||
bg_band->channels[i].hw_value = geo->bg[i].channel;
|
||||
bg_band->channels[i].max_power = geo->bg[i].max_power;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_NO_IBSS;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_RADAR;
|
||||
/* No equivalent for LIBIPW_CH_80211H_RULES,
|
||||
LIBIPW_CH_UNIFORM_SPREADING, or
|
||||
LIBIPW_CH_B_ONLY... */
|
||||
}
|
||||
/* point at bitrate info */
|
||||
bg_band->bitrates = ipw2200_bg_rates;
|
||||
bg_band->n_bitrates = ipw2200_num_bg_rates;
|
||||
|
||||
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
|
||||
}
|
||||
|
||||
/* fill-out priv->ieee->a_band */
|
||||
if (geo->a_channels) {
|
||||
struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
|
||||
|
||||
a_band->band = IEEE80211_BAND_5GHZ;
|
||||
a_band->n_channels = geo->a_channels;
|
||||
a_band->channels =
|
||||
kzalloc(geo->a_channels *
|
||||
sizeof(struct ieee80211_channel), GFP_KERNEL);
|
||||
/* translate geo->bg to a_band.channels */
|
||||
for (i = 0; i < geo->a_channels; i++) {
|
||||
a_band->channels[i].band = IEEE80211_BAND_2GHZ;
|
||||
a_band->channels[i].center_freq = geo->a[i].freq;
|
||||
a_band->channels[i].hw_value = geo->a[i].channel;
|
||||
a_band->channels[i].max_power = geo->a[i].max_power;
|
||||
if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
|
||||
a_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
|
||||
a_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_NO_IBSS;
|
||||
if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
|
||||
a_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_RADAR;
|
||||
/* No equivalent for LIBIPW_CH_80211H_RULES,
|
||||
LIBIPW_CH_UNIFORM_SPREADING, or
|
||||
LIBIPW_CH_B_ONLY... */
|
||||
}
|
||||
/* point at bitrate info */
|
||||
a_band->bitrates = ipw2200_a_rates;
|
||||
a_band->n_bitrates = ipw2200_num_a_rates;
|
||||
|
||||
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band;
|
||||
}
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
|
||||
|
||||
/* With that information in place, we can now register the wiphy... */
|
||||
if (wiphy_register(wdev->wiphy)) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* PCI driver stuff */
|
||||
|
@ -11562,7 +11651,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
|
|||
if (priv->prom_net_dev)
|
||||
return -EPERM;
|
||||
|
||||
priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv));
|
||||
priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1);
|
||||
if (priv->prom_net_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -11581,7 +11670,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
|
|||
|
||||
rc = register_netdev(priv->prom_net_dev);
|
||||
if (rc) {
|
||||
free_ieee80211(priv->prom_net_dev);
|
||||
free_ieee80211(priv->prom_net_dev, 1);
|
||||
priv->prom_net_dev = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
@ -11595,7 +11684,7 @@ static void ipw_prom_free(struct ipw_priv *priv)
|
|||
return;
|
||||
|
||||
unregister_netdev(priv->prom_net_dev);
|
||||
free_ieee80211(priv->prom_net_dev);
|
||||
free_ieee80211(priv->prom_net_dev, 1);
|
||||
|
||||
priv->prom_net_dev = NULL;
|
||||
}
|
||||
|
@ -11623,7 +11712,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
|
|||
struct ipw_priv *priv;
|
||||
int i;
|
||||
|
||||
net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
|
||||
net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0);
|
||||
if (net_dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -11771,7 +11860,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
|
|||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
out_free_ieee80211:
|
||||
free_ieee80211(priv->net_dev);
|
||||
free_ieee80211(priv->net_dev, 0);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -11838,7 +11927,11 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
|
|||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
free_ieee80211(priv->net_dev);
|
||||
/* wiphy_unregister needs to be here, before free_ieee80211 */
|
||||
wiphy_unregister(priv->ieee->wdev.wiphy);
|
||||
kfree(priv->ieee->a_band.channels);
|
||||
kfree(priv->ieee->bg_band.channels);
|
||||
free_ieee80211(priv->net_dev, 0);
|
||||
free_firmware();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/ieee80211.h>
|
||||
|
||||
#include <net/lib80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#define LIBIPW_VERSION "git-1.1.13"
|
||||
|
||||
|
@ -783,12 +784,15 @@ struct libipw_geo {
|
|||
|
||||
struct libipw_device {
|
||||
struct net_device *dev;
|
||||
struct wireless_dev wdev;
|
||||
struct libipw_security sec;
|
||||
|
||||
/* Bookkeeping structures */
|
||||
struct libipw_stats ieee_stats;
|
||||
|
||||
struct libipw_geo geo;
|
||||
struct ieee80211_supported_band bg_band;
|
||||
struct ieee80211_supported_band a_band;
|
||||
|
||||
/* Probe / Beacon management */
|
||||
struct list_head network_free_list;
|
||||
|
@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate)
|
|||
}
|
||||
|
||||
/* ieee80211.c */
|
||||
extern void free_ieee80211(struct net_device *dev);
|
||||
extern struct net_device *alloc_ieee80211(int sizeof_priv);
|
||||
extern void free_ieee80211(struct net_device *dev, int monitor);
|
||||
extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
|
||||
extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
|
||||
|
||||
extern void libipw_networks_age(struct libipw_device *ieee,
|
||||
|
|
|
@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
|||
MODULE_AUTHOR(DRV_COPYRIGHT);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct cfg80211_ops libipw_config_ops = { };
|
||||
void *libipw_wiphy_privid = &libipw_wiphy_privid;
|
||||
|
||||
static int libipw_networks_allocate(struct libipw_device *ieee)
|
||||
{
|
||||
if (ieee->networks)
|
||||
|
@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu)
|
|||
}
|
||||
EXPORT_SYMBOL(libipw_change_mtu);
|
||||
|
||||
struct net_device *alloc_ieee80211(int sizeof_priv)
|
||||
struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
|
||||
{
|
||||
struct libipw_device *ieee;
|
||||
struct net_device *dev;
|
||||
|
@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
|
|||
|
||||
ieee->dev = dev;
|
||||
|
||||
if (!monitor) {
|
||||
ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
|
||||
if (!ieee->wdev.wiphy) {
|
||||
LIBIPW_ERROR("Unable to allocate wiphy.\n");
|
||||
goto failed_free_netdev;
|
||||
}
|
||||
|
||||
ieee->dev->ieee80211_ptr = &ieee->wdev;
|
||||
ieee->wdev.iftype = NL80211_IFTYPE_STATION;
|
||||
|
||||
/* Fill-out wiphy structure bits we know... Not enough info
|
||||
here to call set_wiphy_dev or set MAC address or channel info
|
||||
-- have to do that in ->ndo_init... */
|
||||
ieee->wdev.wiphy->privid = libipw_wiphy_privid;
|
||||
|
||||
ieee->wdev.wiphy->max_scan_ssids = 1;
|
||||
ieee->wdev.wiphy->max_scan_ie_len = 0;
|
||||
ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
|
||||
| BIT(NL80211_IFTYPE_ADHOC);
|
||||
}
|
||||
|
||||
err = libipw_networks_allocate(ieee);
|
||||
if (err) {
|
||||
LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
|
||||
goto failed_free_netdev;
|
||||
goto failed_free_wiphy;
|
||||
}
|
||||
libipw_networks_initialize(ieee);
|
||||
|
||||
|
@ -193,19 +217,27 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
|
|||
|
||||
return dev;
|
||||
|
||||
failed_free_wiphy:
|
||||
if (!monitor)
|
||||
wiphy_free(ieee->wdev.wiphy);
|
||||
failed_free_netdev:
|
||||
free_netdev(dev);
|
||||
failed:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_ieee80211(struct net_device *dev)
|
||||
void free_ieee80211(struct net_device *dev, int monitor)
|
||||
{
|
||||
struct libipw_device *ieee = netdev_priv(dev);
|
||||
|
||||
lib80211_crypt_info_free(&ieee->crypt_info);
|
||||
|
||||
libipw_networks_free(ieee);
|
||||
|
||||
/* free cfg80211 resources */
|
||||
if (!monitor)
|
||||
wiphy_free(ieee->wdev.wiphy);
|
||||
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -173,6 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
|
|||
.use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl1000_bg_cfg = {
|
||||
|
|
|
@ -221,22 +221,13 @@ struct iwl3945_ibss_seq {
|
|||
* for use by iwl-*.c
|
||||
*
|
||||
*****************************************************************************/
|
||||
extern int iwl3945_power_init_handle(struct iwl_priv *priv);
|
||||
extern int iwl3945_eeprom_init(struct iwl_priv *priv);
|
||||
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
|
||||
extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
|
||||
extern int iwl3945_tx_queue_init(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq, int count, u32 id);
|
||||
extern void iwl3945_rx_replenish(void *data);
|
||||
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
||||
extern void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
|
||||
extern int iwl3945_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
|
||||
const void *data);
|
||||
extern int __must_check iwl3945_send_cmd(struct iwl_priv *priv,
|
||||
struct iwl_host_cmd *cmd);
|
||||
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,int left);
|
||||
extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv);
|
||||
extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
|
||||
extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1818,8 +1818,9 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
|||
addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
|
||||
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
|
||||
addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
|
||||
addsta->sleep_tx_count = cmd->sleep_tx_count;
|
||||
addsta->reserved1 = cpu_to_le16(0);
|
||||
addsta->reserved2 = cpu_to_le32(0);
|
||||
addsta->reserved2 = cpu_to_le16(0);
|
||||
|
||||
return (u16)sizeof(struct iwl4965_addsta_cmd);
|
||||
}
|
||||
|
@ -1865,8 +1866,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
|
|||
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
info->flags |= iwl_is_tx_success(status) ?
|
||||
IEEE80211_TX_STAT_ACK : 0;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
||||
/* FIXME: code repetition end */
|
||||
|
||||
|
@ -2021,8 +2021,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
|||
}
|
||||
} else {
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags |= iwl_is_tx_success(status) ?
|
||||
IEEE80211_TX_STAT_ACK : 0;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwl_hwrate_to_tx_control(priv,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
info);
|
||||
|
@ -2240,6 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
|
|||
.broken_powersave = true,
|
||||
.led_compensation = 61,
|
||||
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
/* Module firmware */
|
||||
|
|
|
@ -994,8 +994,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
|
|||
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
info->flags |= iwl_is_tx_success(status) ?
|
||||
IEEE80211_TX_STAT_ACK : 0;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
||||
|
||||
/* FIXME: code repetition end */
|
||||
|
@ -1140,8 +1139,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
|
|||
BUG_ON(txq_id != txq->swq_id);
|
||||
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
info->flags |= iwl_is_tx_success(status) ?
|
||||
IEEE80211_TX_STAT_ACK : 0;
|
||||
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||
iwl_hwrate_to_tx_control(priv,
|
||||
le32_to_cpu(tx_resp->rate_n_flags),
|
||||
info);
|
||||
|
@ -1251,6 +1249,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv)
|
|||
|
||||
/* half dBm need to multiply */
|
||||
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
|
||||
|
||||
if (priv->tx_power_lmt_in_half_dbm &&
|
||||
priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
|
||||
/*
|
||||
* For the newer devices which using enhanced/extend tx power
|
||||
* table in EEPROM, the format is in half dBm. driver need to
|
||||
* convert to dBm format before report to mac80211.
|
||||
* By doing so, there is a possibility of 1/2 dBm resolution
|
||||
* lost. driver will perform "round-up" operation before
|
||||
* reporting, but it will cause 1/2 dBm tx power over the
|
||||
* regulatory limit. Perform the checking here, if the
|
||||
* "tx_power_user_lmt" is higher than EEPROM value (in
|
||||
* half-dBm format), lower the tx power based on EEPROM
|
||||
*/
|
||||
tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
|
||||
}
|
||||
tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
|
||||
tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
|
||||
|
||||
|
@ -1584,14 +1598,15 @@ struct iwl_cfg iwl5300_agn_cfg = {
|
|||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5100_bg_cfg = {
|
||||
.name = "5100BG",
|
||||
struct iwl_cfg iwl5100_bgn_cfg = {
|
||||
.name = "5100BGN",
|
||||
.fw_name_pre = IWL5000_FW_PRE,
|
||||
.ucode_api_max = IWL5000_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL5000_UCODE_API_MIN,
|
||||
.sku = IWL_SKU_G,
|
||||
.sku = IWL_SKU_G|IWL_SKU_N,
|
||||
.ops = &iwl5000_ops,
|
||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
||||
|
@ -1627,7 +1642,6 @@ struct iwl_cfg iwl5100_abg_cfg = {
|
|||
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
||||
.set_l0s = true,
|
||||
.use_bsm = false,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
};
|
||||
|
@ -1653,6 +1667,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
|
|||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5350_agn_cfg = {
|
||||
|
@ -1676,6 +1691,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
|
|||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5150_agn_cfg = {
|
||||
|
@ -1699,6 +1715,29 @@ struct iwl_cfg iwl5150_agn_cfg = {
|
|||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl5150_abg_cfg = {
|
||||
.name = "5150ABG",
|
||||
.fw_name_pre = IWL5150_FW_PRE,
|
||||
.ucode_api_max = IWL5150_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL5150_UCODE_API_MIN,
|
||||
.sku = IWL_SKU_A|IWL_SKU_G,
|
||||
.ops = &iwl5150_ops,
|
||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
|
||||
.num_of_queues = IWL50_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
|
||||
.mod_params = &iwl50_mod_params,
|
||||
.valid_tx_ant = ANT_A,
|
||||
.valid_rx_ant = ANT_AB,
|
||||
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
||||
.set_l0s = true,
|
||||
.use_bsm = false,
|
||||
.led_compensation = 51,
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
|
||||
|
|
|
@ -306,6 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
|
|||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6000i_2abg_cfg = {
|
||||
|
@ -394,8 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
|
|||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.support_sm_ps = true,
|
||||
.support_wimax_coexist = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6050_2abg_cfg = {
|
||||
|
@ -425,7 +425,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
|
|||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.support_wimax_coexist = true,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6000_3agn_cfg = {
|
||||
|
@ -456,38 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
|
|||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
};
|
||||
|
||||
struct iwl_cfg iwl6050_3agn_cfg = {
|
||||
.name = "6050 Series 3x3 AGN",
|
||||
.fw_name_pre = IWL6050_FW_PRE,
|
||||
.ucode_api_max = IWL6050_UCODE_API_MAX,
|
||||
.ucode_api_min = IWL6050_UCODE_API_MIN,
|
||||
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
||||
.ops = &iwl6050_ops,
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
|
||||
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
||||
.num_of_queues = IWL50_NUM_QUEUES,
|
||||
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
|
||||
.mod_params = &iwl50_mod_params,
|
||||
.valid_tx_ant = ANT_ABC,
|
||||
.valid_rx_ant = ANT_ABC,
|
||||
.pll_cfg_val = 0,
|
||||
.set_l0s = true,
|
||||
.use_bsm = false,
|
||||
.pa_type = IWL_PA_SYSTEM,
|
||||
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
|
||||
.shadow_ram_support = true,
|
||||
.ht_greenfield_support = true,
|
||||
.led_compensation = 51,
|
||||
.use_rts_for_ht = true, /* use rts/cts protection */
|
||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||
.supports_idle = true,
|
||||
.adv_thermal_throttle = true,
|
||||
.support_ct_kill_exit = true,
|
||||
.support_sm_ps = true,
|
||||
.support_wimax_coexist = true,
|
||||
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
||||
|
|
|
@ -301,7 +301,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
|
|||
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
|
||||
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
|
||||
sta->addr, tid);
|
||||
ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
|
||||
ieee80211_start_tx_ba_session(sta, tid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2964,16 +2964,16 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
|
|||
{
|
||||
struct iwl_lq_sta *lq_sta = priv_sta;
|
||||
lq_sta->rs_sta_dbgfs_scale_table_file =
|
||||
debugfs_create_file("rate_scale_table", 0600, dir,
|
||||
debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
|
||||
lq_sta, &rs_sta_dbgfs_scale_table_ops);
|
||||
lq_sta->rs_sta_dbgfs_stats_table_file =
|
||||
debugfs_create_file("rate_stats_table", 0600, dir,
|
||||
debugfs_create_file("rate_stats_table", S_IRUSR, dir,
|
||||
lq_sta, &rs_sta_dbgfs_stats_table_ops);
|
||||
lq_sta->rs_sta_dbgfs_rate_scale_data_file =
|
||||
debugfs_create_file("rate_scale_data", 0600, dir,
|
||||
debugfs_create_file("rate_scale_data", S_IRUSR, dir,
|
||||
lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
|
||||
lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
|
||||
debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
|
||||
debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
|
||||
&lq_sta->tx_agg_tid_en);
|
||||
|
||||
}
|
||||
|
|
|
@ -311,7 +311,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
|
|||
list_add(&frame->list, &priv->free_frames);
|
||||
}
|
||||
|
||||
static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
|
||||
static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
|
||||
struct ieee80211_hdr *hdr,
|
||||
int left)
|
||||
{
|
||||
|
@ -328,34 +328,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
|
|||
return priv->ibss_beacon->len;
|
||||
}
|
||||
|
||||
/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
|
||||
static void iwl_set_beacon_tim(struct iwl_priv *priv,
|
||||
struct iwl_tx_beacon_cmd *tx_beacon_cmd,
|
||||
u8 *beacon, u32 frame_size)
|
||||
{
|
||||
u16 tim_idx;
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
|
||||
|
||||
/*
|
||||
* The index is relative to frame start but we start looking at the
|
||||
* variable-length part of the beacon.
|
||||
*/
|
||||
tim_idx = mgmt->u.beacon.variable - beacon;
|
||||
|
||||
/* Parse variable-length elements of beacon to find WLAN_EID_TIM */
|
||||
while ((tim_idx < (frame_size - 2)) &&
|
||||
(beacon[tim_idx] != WLAN_EID_TIM))
|
||||
tim_idx += beacon[tim_idx+1] + 2;
|
||||
|
||||
/* If TIM field was found, set variables */
|
||||
if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
|
||||
tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
|
||||
tx_beacon_cmd->tim_size = beacon[tim_idx+1];
|
||||
} else
|
||||
IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
|
||||
}
|
||||
|
||||
static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
|
||||
struct iwl_frame *frame, u8 rate)
|
||||
struct iwl_frame *frame)
|
||||
{
|
||||
struct iwl_tx_beacon_cmd *tx_beacon_cmd;
|
||||
unsigned int frame_size;
|
||||
u32 frame_size;
|
||||
u32 rate_flags;
|
||||
u32 rate;
|
||||
/*
|
||||
* We have to set up the TX command, the TX Beacon command, and the
|
||||
* beacon contents.
|
||||
*/
|
||||
|
||||
/* Initialize memory */
|
||||
tx_beacon_cmd = &frame->u.beacon;
|
||||
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
|
||||
|
||||
tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
|
||||
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
||||
|
||||
/* Set up TX beacon contents */
|
||||
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
|
||||
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
|
||||
if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
|
||||
return 0;
|
||||
|
||||
BUG_ON(frame_size > MAX_MPDU_SIZE);
|
||||
/* Set up TX command fields */
|
||||
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
|
||||
|
||||
if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
|
||||
tx_beacon_cmd->tx.rate_n_flags =
|
||||
iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
|
||||
else
|
||||
tx_beacon_cmd->tx.rate_n_flags =
|
||||
iwl_hw_set_rate_n_flags(rate, 0);
|
||||
|
||||
tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
|
||||
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
||||
tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
|
||||
TX_CMD_FLG_TSF_MSK |
|
||||
TX_CMD_FLG_STA_RATE_MSK;
|
||||
TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
|
||||
|
||||
/* Set up TX beacon command fields */
|
||||
iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
|
||||
frame_size);
|
||||
|
||||
/* Set up packet rate and flags */
|
||||
rate = iwl_rate_get_lowest_plcp(priv);
|
||||
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
|
||||
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
|
||||
if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
|
||||
rate_flags |= RATE_MCS_CCK_MSK;
|
||||
tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
|
||||
rate_flags);
|
||||
|
||||
return sizeof(*tx_beacon_cmd) + frame_size;
|
||||
}
|
||||
|
@ -364,19 +404,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
|
|||
struct iwl_frame *frame;
|
||||
unsigned int frame_size;
|
||||
int rc;
|
||||
u8 rate;
|
||||
|
||||
frame = iwl_get_free_frame(priv);
|
||||
|
||||
if (!frame) {
|
||||
IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
|
||||
"command.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rate = iwl_rate_get_lowest_plcp(priv);
|
||||
|
||||
frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
|
||||
frame_size = iwl_hw_get_beacon_cmd(priv, frame);
|
||||
if (!frame_size) {
|
||||
IWL_ERR(priv, "Error configuring the beacon command\n");
|
||||
iwl_free_frame(priv, frame);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
|
||||
&frame->u.cmd[0]);
|
||||
|
@ -613,7 +654,7 @@ static void iwl_bg_statistics_periodic(unsigned long data)
|
|||
if (!iwl_is_ready_rf(priv))
|
||||
return;
|
||||
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC);
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC, false);
|
||||
}
|
||||
|
||||
static void iwl_rx_beacon_notif(struct iwl_priv *priv,
|
||||
|
@ -730,7 +771,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
|
|||
* statistics request from the host as well as for the periodic
|
||||
* statistics notifications (after received beacons) from the uCode.
|
||||
*/
|
||||
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics;
|
||||
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics;
|
||||
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
|
||||
|
||||
iwl_setup_spectrum_handlers(priv);
|
||||
|
@ -1038,7 +1079,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
|
|||
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
|
||||
iwl_rx_handle(priv);
|
||||
priv->isr_stats.rx++;
|
||||
iwl_leds_background(priv);
|
||||
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
|
||||
}
|
||||
|
||||
|
@ -1226,19 +1266,27 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
|
|||
* 3- update RX shared data to indicate last write index.
|
||||
* 4- send interrupt.
|
||||
* This could lead to RX race, driver could receive RX interrupt
|
||||
* but the shared data changes does not reflect this.
|
||||
* this could lead to RX race, RX periodic will solve this race
|
||||
* but the shared data changes does not reflect this;
|
||||
* periodic interrupt will detect any dangling Rx activity.
|
||||
*/
|
||||
iwl_write32(priv, CSR_INT_PERIODIC_REG,
|
||||
|
||||
/* Disable periodic interrupt; we use it as just a one-shot. */
|
||||
iwl_write8(priv, CSR_INT_PERIODIC_REG,
|
||||
CSR_INT_PERIODIC_DIS);
|
||||
iwl_rx_handle(priv);
|
||||
/* Only set RX periodic if real RX is received. */
|
||||
|
||||
/*
|
||||
* Enable periodic interrupt in 8 msec only if we received
|
||||
* real RX interrupt (instead of just periodic int), to catch
|
||||
* any dangling Rx interrupt. If it was just the periodic
|
||||
* interrupt, there was no dangling Rx activity, and no need
|
||||
* to extend the periodic interrupt; one-shot is enough.
|
||||
*/
|
||||
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
|
||||
iwl_write32(priv, CSR_INT_PERIODIC_REG,
|
||||
iwl_write8(priv, CSR_INT_PERIODIC_REG,
|
||||
CSR_INT_PERIODIC_ENA);
|
||||
|
||||
priv->isr_stats.rx++;
|
||||
iwl_leds_background(priv);
|
||||
}
|
||||
|
||||
/* This "Tx" DMA channel is used only for loading uCode */
|
||||
|
@ -1557,7 +1605,6 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static const char *desc_lookup_text[] = {
|
||||
"OK",
|
||||
"FAIL",
|
||||
|
@ -1710,10 +1757,42 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
|||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_print_last_event_logs - Dump the newest # of event log to syslog
|
||||
*/
|
||||
static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
u32 num_wraps, u32 next_entry,
|
||||
u32 size, u32 mode)
|
||||
{
|
||||
/*
|
||||
* display the newest DEFAULT_LOG_ENTRIES entries
|
||||
* i.e the entries just before the next ont that uCode would fill.
|
||||
*/
|
||||
if (num_wraps) {
|
||||
if (next_entry < size) {
|
||||
iwl_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode);
|
||||
iwl_print_event_log(priv, 0,
|
||||
next_entry, mode);
|
||||
} else
|
||||
iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
} else {
|
||||
if (next_entry < size)
|
||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
else
|
||||
iwl_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||
#define MAX_EVENT_LOG_SIZE (512)
|
||||
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
||||
#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
|
||||
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
{
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
u32 capacity; /* event log capacity in # entries */
|
||||
|
@ -1758,19 +1837,37 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
|||
return;
|
||||
}
|
||||
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
|
||||
size, num_wraps);
|
||||
|
||||
/* if uCode has wrapped back to top of log, start at the oldest entry,
|
||||
* i.e the next one that uCode would fill. */
|
||||
if (num_wraps)
|
||||
iwl_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode);
|
||||
/* (then/else) start at top of log */
|
||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS))
|
||||
size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
|
||||
? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
|
||||
#else
|
||||
size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
|
||||
? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
|
||||
#endif
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
|
||||
size);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
|
||||
/*
|
||||
* if uCode has wrapped back to top of log,
|
||||
* start at the oldest entry,
|
||||
* i.e the next one that uCode would fill.
|
||||
*/
|
||||
if (num_wraps)
|
||||
iwl_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode);
|
||||
/* (then/else) start at top of log */
|
||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
||||
} else
|
||||
iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
#else
|
||||
iwl_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_alive_start - called after REPLY_ALIVE notification received
|
||||
|
@ -2360,16 +2457,14 @@ static int iwl_setup_mac(struct iwl_priv *priv)
|
|||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
|
||||
/* Firmware does not support this */
|
||||
hw->wiphy->disable_beacon_hints = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||
|
||||
/*
|
||||
* For now, disable PS by default because it affects
|
||||
* RX performance significantly.
|
||||
*/
|
||||
hw->wiphy->ps_default = false;
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
|
||||
/* we create the 802.11 header and a zero-length SSID element */
|
||||
|
@ -2523,6 +2618,10 @@ void iwl_config_ap(struct iwl_priv *priv)
|
|||
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||
"Attempting to continue.\n");
|
||||
|
||||
/* AP has all antennas */
|
||||
priv->chain_noise_data.active_chains =
|
||||
priv->hw_params.valid_rx_ant;
|
||||
iwl_set_rxon_ht(priv, &priv->current_ht_config);
|
||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||
priv->cfg->ops->hcmd->set_rxon_chain(priv);
|
||||
|
||||
|
@ -2551,6 +2650,7 @@ void iwl_config_ap(struct iwl_priv *priv)
|
|||
/* restore RXON assoc */
|
||||
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||
iwlcore_commit_rxon(priv);
|
||||
iwl_reset_qos(priv);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
iwl_activate_qos(priv, 1);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
@ -2646,6 +2746,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
}
|
||||
|
||||
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
{
|
||||
|
@ -2699,6 +2800,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd cmd,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
|
||||
int sta_id;
|
||||
|
||||
/*
|
||||
* TODO: We really should use this callback to
|
||||
* actually maintain the station table in
|
||||
* the device.
|
||||
*/
|
||||
|
||||
switch (cmd) {
|
||||
case STA_NOTIFY_ADD:
|
||||
atomic_set(&sta_priv->pending_frames, 0);
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
sta_priv->client = true;
|
||||
break;
|
||||
case STA_NOTIFY_SLEEP:
|
||||
WARN_ON(!sta_priv->client);
|
||||
sta_priv->asleep = true;
|
||||
if (atomic_read(&sta_priv->pending_frames) > 0)
|
||||
ieee80211_sta_block_awake(hw, sta, true);
|
||||
break;
|
||||
case STA_NOTIFY_AWAKE:
|
||||
WARN_ON(!sta_priv->client);
|
||||
sta_priv->asleep = false;
|
||||
sta_id = iwl_find_station(priv, sta->addr);
|
||||
if (sta_id != IWL_INVALID_STATION)
|
||||
iwl_sta_modify_ps_wake(priv, sta_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* sysfs attributes
|
||||
|
@ -2893,7 +3033,7 @@ static ssize_t show_statistics(struct device *d,
|
|||
return -EAGAIN;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
rc = iwl_send_statistics_request(priv, 0);
|
||||
rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (rc) {
|
||||
|
@ -3045,10 +3185,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
|
|||
priv->band = IEEE80211_BAND_2GHZ;
|
||||
|
||||
priv->iw_mode = NL80211_IFTYPE_STATION;
|
||||
if (priv->cfg->support_sm_ps)
|
||||
priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC;
|
||||
else
|
||||
priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
|
||||
|
||||
/* Choose which receivers/antennas to use */
|
||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||
|
@ -3130,7 +3266,8 @@ static struct ieee80211_ops iwl_hw_ops = {
|
|||
.reset_tsf = iwl_mac_reset_tsf,
|
||||
.bss_info_changed = iwl_bss_info_changed,
|
||||
.ampdu_action = iwl_mac_ampdu_action,
|
||||
.hw_scan = iwl_mac_hw_scan
|
||||
.hw_scan = iwl_mac_hw_scan,
|
||||
.sta_notify = iwl_mac_sta_notify,
|
||||
};
|
||||
|
||||
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
@ -3454,23 +3591,63 @@ static struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||
#endif /* CONFIG_IWL4965 */
|
||||
#ifdef CONFIG_IWL5000
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
|
||||
/* 5350 WiFi/WiMax */
|
||||
{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
|
||||
/* 5150 Wifi/WiMax */
|
||||
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
|
||||
/* 5100 Series WiFi */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
|
||||
|
||||
/* 5300 Series WiFi */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
|
||||
|
||||
/* 5350 Series WiFi/WiMax */
|
||||
{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
|
||||
|
||||
/* 5150 Series Wifi/WiMax */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
|
||||
|
||||
{IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
|
||||
{IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
|
||||
|
||||
/* 6x00 Series */
|
||||
{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
|
||||
|
@ -3485,13 +3662,10 @@ static struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
|
||||
|
||||
/* 6x50 WiFi/WiMax Series */
|
||||
{IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
|
||||
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
|
||||
|
||||
|
|
|
@ -900,7 +900,7 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv)
|
|||
|
||||
/* Ask for statistics now, the uCode will send notification
|
||||
* periodically after association */
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC);
|
||||
iwl_send_statistics_request(priv, CMD_ASYNC, true);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_reset_run_time_calib);
|
||||
|
||||
|
|
|
@ -977,6 +977,7 @@ struct iwl_qosparam_cmd {
|
|||
#define STA_MODIFY_TX_RATE_MSK 0x04
|
||||
#define STA_MODIFY_ADDBA_TID_MSK 0x08
|
||||
#define STA_MODIFY_DELBA_TID_MSK 0x10
|
||||
#define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20
|
||||
|
||||
/* Receiver address (actually, Rx station's index into station table),
|
||||
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
|
||||
|
@ -1107,7 +1108,14 @@ struct iwl4965_addsta_cmd {
|
|||
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
||||
__le16 add_immediate_ba_ssn;
|
||||
|
||||
__le32 reserved2;
|
||||
/*
|
||||
* Number of packets OK to transmit to station even though
|
||||
* it is asleep -- used to synchronise PS-poll and u-APSD
|
||||
* responses while ucode keeps track of STA sleep state.
|
||||
*/
|
||||
__le16 sleep_tx_count;
|
||||
|
||||
__le16 reserved2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* 5000 */
|
||||
|
@ -1138,7 +1146,14 @@ struct iwl_addsta_cmd {
|
|||
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
||||
__le16 add_immediate_ba_ssn;
|
||||
|
||||
__le32 reserved2;
|
||||
/*
|
||||
* Number of packets OK to transmit to station even though
|
||||
* it is asleep -- used to synchronise PS-poll and u-APSD
|
||||
* responses while ucode keeps track of STA sleep state.
|
||||
*/
|
||||
__le16 sleep_tx_count;
|
||||
|
||||
__le16 reserved2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
|
@ -1690,6 +1705,21 @@ enum {
|
|||
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
|
||||
};
|
||||
|
||||
static inline u32 iwl_tx_status_to_mac80211(u32 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
|
||||
switch (status) {
|
||||
case TX_STATUS_SUCCESS:
|
||||
case TX_STATUS_DIRECT_DONE:
|
||||
return IEEE80211_TX_STAT_ACK;
|
||||
case TX_STATUS_FAIL_DEST_PS:
|
||||
return IEEE80211_TX_STAT_TX_FILTERED;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool iwl_is_tx_success(u32 status)
|
||||
{
|
||||
status &= TX_STATUS_MSK;
|
||||
|
@ -3071,6 +3101,10 @@ struct statistics_general {
|
|||
__le32 reserved3;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
|
||||
#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
|
||||
#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2)
|
||||
|
||||
/*
|
||||
* REPLY_STATISTICS_CMD = 0x9c,
|
||||
* 3945 and 4965 identical.
|
||||
|
|
|
@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
|
|||
}
|
||||
return ant;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_toggle_tx_ant);
|
||||
|
||||
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
EXPORT_SYMBOL(iwl_bcast_addr);
|
||||
|
@ -255,7 +256,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
|
|||
/* nic_init */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
||||
iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
|
||||
|
||||
/* Set interrupt coalescing timer to 512 usecs */
|
||||
iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
|
||||
|
@ -446,13 +450,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
|
|||
if (priv->cfg->ht_greenfield_support)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
if (priv->cfg->support_sm_ps)
|
||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
||||
(WLAN_HT_CAP_SM_PS_DYNAMIC << 2));
|
||||
else
|
||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
||||
(WLAN_HT_CAP_SM_PS_DISABLED << 2));
|
||||
|
||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
||||
(priv->cfg->sm_ps_mode << 2));
|
||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
|
@ -1007,25 +1006,23 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
|
|||
int idle_cnt = active_cnt;
|
||||
bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
|
||||
|
||||
if (priv->cfg->support_sm_ps) {
|
||||
/* # Rx chains when idling and maybe trying to save power */
|
||||
switch (priv->current_ht_config.sm_ps) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||
idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
|
||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||
idle_cnt = (is_cam) ? active_cnt :
|
||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_INVALID:
|
||||
default:
|
||||
IWL_ERR(priv, "invalid sm_ps mode %d\n",
|
||||
priv->current_ht_config.sm_ps);
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
/* # Rx chains when idling and maybe trying to save power */
|
||||
switch (priv->cfg->sm_ps_mode) {
|
||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
||||
idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||
idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
|
||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||
break;
|
||||
case WLAN_HT_CAP_SM_PS_INVALID:
|
||||
default:
|
||||
IWL_ERR(priv, "invalid sm_ps mode %u\n",
|
||||
priv->cfg->sm_ps_mode);
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
return idle_cnt;
|
||||
}
|
||||
|
@ -1365,12 +1362,11 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
|
|||
/* Cancel currently queued command. */
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||
|
||||
priv->cfg->ops->lib->dump_nic_error_log(priv);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, false);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) {
|
||||
priv->cfg->ops->lib->dump_nic_error_log(priv);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv);
|
||||
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
|
||||
iwl_print_rx_config_cmd(priv);
|
||||
}
|
||||
#endif
|
||||
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
|
@ -1991,16 +1987,21 @@ int iwl_send_bt_config(struct iwl_priv *priv)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_send_bt_config);
|
||||
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
|
||||
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
|
||||
{
|
||||
u32 stat_flags = 0;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = REPLY_STATISTICS_CMD,
|
||||
.flags = flags,
|
||||
.len = sizeof(stat_flags),
|
||||
.data = (u8 *) &stat_flags,
|
||||
struct iwl_statistics_cmd statistics_cmd = {
|
||||
.configuration_flags =
|
||||
clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
|
||||
};
|
||||
return iwl_send_cmd(priv, &cmd);
|
||||
|
||||
if (flags & CMD_ASYNC)
|
||||
return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd, NULL);
|
||||
else
|
||||
return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
|
||||
sizeof(struct iwl_statistics_cmd),
|
||||
&statistics_cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_send_statistics_request);
|
||||
|
||||
|
@ -2477,6 +2478,16 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
|||
} else {
|
||||
priv->assoc_id = 0;
|
||||
iwl_led_disassociate(priv);
|
||||
|
||||
/*
|
||||
* inform the ucode that there is no longer an
|
||||
* association and that no more packets should be
|
||||
* send
|
||||
*/
|
||||
priv->staging_rxon.filter_flags &=
|
||||
~RXON_FILTER_ASSOC_MSK;
|
||||
priv->staging_rxon.assoc_id = 0;
|
||||
iwlcore_commit_rxon(priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2492,6 +2503,14 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
if ((changes & BSS_CHANGED_BEACON_ENABLED) &&
|
||||
vif->bss_conf.enable_beacon) {
|
||||
memcpy(priv->staging_rxon.bssid_addr,
|
||||
bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
iwlcore_config_ap(priv);
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
|
@ -3070,15 +3089,11 @@ const char *get_ctrl_string(int cmd)
|
|||
}
|
||||
}
|
||||
|
||||
void iwl_clear_tx_stats(struct iwl_priv *priv)
|
||||
void iwl_clear_traffic_stats(struct iwl_priv *priv)
|
||||
{
|
||||
memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
|
||||
|
||||
}
|
||||
|
||||
void iwl_clear_rx_stats(struct iwl_priv *priv)
|
||||
{
|
||||
memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
|
||||
priv->led_tpt = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3171,6 +3186,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
|
|||
stats->data_cnt++;
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
iwl_leds_background(priv);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_update_stats);
|
||||
#endif
|
||||
|
|
|
@ -167,7 +167,7 @@ struct iwl_lib_ops {
|
|||
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||
/* 1st ucode load */
|
||||
int (*load_ucode)(struct iwl_priv *priv);
|
||||
void (*dump_nic_event_log)(struct iwl_priv *priv);
|
||||
void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
|
||||
void (*dump_nic_error_log)(struct iwl_priv *priv);
|
||||
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
|
||||
/* power management */
|
||||
|
@ -228,7 +228,7 @@ struct iwl_mod_params {
|
|||
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
||||
* @adv_thermal_throttle: support advance thermal throttle
|
||||
* @support_ct_kill_exit: support ct kill exit condition
|
||||
* @support_sm_ps: support spatial multiplexing power save
|
||||
* @sm_ps_mode: spatial multiplexing power save mode
|
||||
* @support_wimax_coexist: support wimax/wifi co-exist
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt API version. The
|
||||
|
@ -285,7 +285,7 @@ struct iwl_cfg {
|
|||
const bool supports_idle;
|
||||
bool adv_thermal_throttle;
|
||||
bool support_ct_kill_exit;
|
||||
bool support_sm_ps;
|
||||
u8 sm_ps_mode;
|
||||
const bool support_wimax_coexist;
|
||||
};
|
||||
|
||||
|
@ -353,8 +353,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
|
|||
u16 length, struct ieee80211_hdr *header);
|
||||
const char *get_mgmt_string(int cmd);
|
||||
const char *get_ctrl_string(int cmd);
|
||||
void iwl_clear_tx_stats(struct iwl_priv *priv);
|
||||
void iwl_clear_rx_stats(struct iwl_priv *priv);
|
||||
void iwl_clear_traffic_stats(struct iwl_priv *priv);
|
||||
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
|
||||
u16 len);
|
||||
#else
|
||||
|
@ -390,6 +389,7 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
|
|||
/* data */
|
||||
stats->data_bytes += len;
|
||||
}
|
||||
iwl_leds_background(priv);
|
||||
}
|
||||
#endif
|
||||
/*****************************************************
|
||||
|
@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
|
|||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_rx_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_reply_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb);
|
||||
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
|
||||
|
||||
/* TX helpers */
|
||||
|
@ -576,19 +578,11 @@ int iwl_pci_resume(struct pci_dev *pdev);
|
|||
/*****************************************************
|
||||
* Error Handling Debugging
|
||||
******************************************************/
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv);
|
||||
void iwl_dump_nic_error_log(struct iwl_priv *priv);
|
||||
void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
void iwl_print_rx_config_cmd(struct iwl_priv *priv);
|
||||
#else
|
||||
static inline void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iwl_dump_nic_error_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
|
@ -669,7 +663,8 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
|
|||
|
||||
extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
||||
extern int iwl_send_bt_config(struct iwl_priv *priv);
|
||||
extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
|
||||
extern int iwl_send_statistics_request(struct iwl_priv *priv,
|
||||
u8 flags, bool clear);
|
||||
extern int iwl_verify_ucode(struct iwl_priv *priv);
|
||||
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||
struct iwl_link_quality_cmd *lq, u8 flags);
|
||||
|
|
|
@ -62,11 +62,29 @@
|
|||
*****************************************************************************/
|
||||
#ifndef __iwl_csr_h__
|
||||
#define __iwl_csr_h__
|
||||
/*=== CSR (control and status registers) ===*/
|
||||
/*
|
||||
* CSR (control and status registers)
|
||||
*
|
||||
* CSR registers are mapped directly into PCI bus space, and are accessible
|
||||
* whenever platform supplies power to device, even when device is in
|
||||
* low power states due to driver-invoked device resets
|
||||
* (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes.
|
||||
*
|
||||
* Use iwl_write32() and iwl_read32() family to access these registers;
|
||||
* these provide simple PCI bus access, without waking up the MAC.
|
||||
* Do not use iwl_write_direct32() family for these registers;
|
||||
* no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ.
|
||||
* The MAC (uCode processor, etc.) does not need to be powered up for accessing
|
||||
* the CSR registers.
|
||||
*
|
||||
* NOTE: Newer devices using one-time-programmable (OTP) memory
|
||||
* require device to be awake in order to read this memory
|
||||
* via CSR_EEPROM and CSR_OTP registers
|
||||
*/
|
||||
#define CSR_BASE (0x000)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
|
||||
#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
|
||||
#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
|
||||
#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
|
||||
#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
|
||||
#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
|
||||
|
@ -74,42 +92,65 @@
|
|||
#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
|
||||
#define CSR_GP_CNTRL (CSR_BASE+0x024)
|
||||
|
||||
/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */
|
||||
#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
|
||||
|
||||
/*
|
||||
* Hardware revision info
|
||||
* Bit fields:
|
||||
* 31-8: Reserved
|
||||
* 7-4: Type of device: 0x0 = 4965, 0xd = 3945
|
||||
* 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions
|
||||
* 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D
|
||||
* 1-0: "Dash" value, as in A-1, etc.
|
||||
* 1-0: "Dash" (-) value, as in A-1, etc.
|
||||
*
|
||||
* NOTE: Revision step affects calculation of CCK txpower for 4965.
|
||||
* NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
|
||||
*/
|
||||
#define CSR_HW_REV (CSR_BASE+0x028)
|
||||
|
||||
/* EEPROM reads */
|
||||
/*
|
||||
* EEPROM and OTP (one-time-programmable) memory reads
|
||||
*
|
||||
* NOTE: For (newer) devices using OTP, device must be awake, initialized via
|
||||
* apm_ops.init() in order to read. Older devices (3945/4965/5000)
|
||||
* use EEPROM and do not require this.
|
||||
*/
|
||||
#define CSR_EEPROM_REG (CSR_BASE+0x02c)
|
||||
#define CSR_EEPROM_GP (CSR_BASE+0x030)
|
||||
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
|
||||
|
||||
#define CSR_GIO_REG (CSR_BASE+0x03C)
|
||||
#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
|
||||
#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
|
||||
|
||||
/*
|
||||
* UCODE-DRIVER GP (general purpose) mailbox registers.
|
||||
* SET/CLR registers set/clear bit(s) if "1" is written.
|
||||
*/
|
||||
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
|
||||
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
|
||||
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
|
||||
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
|
||||
|
||||
#define CSR_LED_REG (CSR_BASE+0x094)
|
||||
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
|
||||
|
||||
/* GIO Chicken Bits (PCI Express bus link power management) */
|
||||
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
|
||||
|
||||
#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
|
||||
/* Analog phase-lock-loop configuration */
|
||||
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
|
||||
|
||||
/*
|
||||
* Indicates hardware rev, to determine CCK backoff for txpower calculation.
|
||||
* CSR Hardware Revision Workaround Register. Indicates hardware rev;
|
||||
* "step" determines CCK backoff for txpower calculation. Used for 4965 only.
|
||||
* See also CSR_HW_REV register.
|
||||
* Bit fields:
|
||||
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
|
||||
* 1-0: "Dash" (-) value, as in C-1, etc.
|
||||
*/
|
||||
#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
|
||||
|
||||
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
|
||||
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
|
||||
|
||||
|
@ -126,14 +167,14 @@
|
|||
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
|
||||
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
|
||||
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000)
|
||||
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
|
||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
|
||||
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
|
||||
|
||||
#define CSR_INT_PERIODIC_DIS (0x00)
|
||||
#define CSR_INT_PERIODIC_ENA (0xFF)
|
||||
#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
|
||||
#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
|
||||
|
||||
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
|
||||
* acknowledged (reset) by host writing "1" to flagged bits. */
|
||||
|
@ -198,7 +239,44 @@
|
|||
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
|
||||
#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
|
||||
|
||||
/* GP (general purpose) CONTROL */
|
||||
/*
|
||||
* GP (general purpose) CONTROL REGISTER
|
||||
* Bit fields:
|
||||
* 27: HW_RF_KILL_SW
|
||||
* Indicates state of (platform's) hardware RF-Kill switch
|
||||
* 26-24: POWER_SAVE_TYPE
|
||||
* Indicates current power-saving mode:
|
||||
* 000 -- No power saving
|
||||
* 001 -- MAC power-down
|
||||
* 010 -- PHY (radio) power-down
|
||||
* 011 -- Error
|
||||
* 9-6: SYS_CONFIG
|
||||
* Indicates current system configuration, reflecting pins on chip
|
||||
* as forced high/low by device circuit board.
|
||||
* 4: GOING_TO_SLEEP
|
||||
* Indicates MAC is entering a power-saving sleep power-down.
|
||||
* Not a good time to access device-internal resources.
|
||||
* 3: MAC_ACCESS_REQ
|
||||
* Host sets this to request and maintain MAC wakeup, to allow host
|
||||
* access to device-internal resources. Host must wait for
|
||||
* MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR
|
||||
* device registers.
|
||||
* 2: INIT_DONE
|
||||
* Host sets this to put device into fully operational D0 power mode.
|
||||
* Host resets this after SW_RESET to put device into low power mode.
|
||||
* 0: MAC_CLOCK_READY
|
||||
* Indicates MAC (ucode processor, etc.) is powered up and can run.
|
||||
* Internal resources are accessible.
|
||||
* NOTE: This does not indicate that the processor is actually running.
|
||||
* NOTE: This does not indicate that 4965 or 3945 has completed
|
||||
* init or post-power-down restore of internal SRAM memory.
|
||||
* Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
|
||||
* SRAM is restored and uCode is in normal operation mode.
|
||||
* Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
|
||||
* do not need to save/restore it.
|
||||
* NOTE: After device reset, this bit remains "0" until host sets
|
||||
* INIT_DONE
|
||||
*/
|
||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
|
||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
|
||||
|
@ -231,28 +309,58 @@
|
|||
#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)
|
||||
|
||||
/* EEPROM GP */
|
||||
#define CSR_EEPROM_GP_VALID_MSK (0x00000007)
|
||||
#define CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */
|
||||
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
|
||||
#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
|
||||
#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
|
||||
|
||||
/* One-time-programmable memory general purpose reg */
|
||||
#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */
|
||||
#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
|
||||
#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */
|
||||
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
|
||||
|
||||
/* GP REG */
|
||||
#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
|
||||
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
|
||||
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
|
||||
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
|
||||
#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
|
||||
|
||||
/* EEPROM signature */
|
||||
#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
|
||||
#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
|
||||
#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
|
||||
|
||||
/* CSR GIO */
|
||||
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
|
||||
|
||||
/* UCODE DRV GP */
|
||||
/*
|
||||
* UCODE-DRIVER GP (general purpose) mailbox register 1
|
||||
* Host driver and uCode write and/or read this register to communicate with
|
||||
* each other.
|
||||
* Bit fields:
|
||||
* 4: UCODE_DISABLE
|
||||
* Host sets this to request permanent halt of uCode, same as
|
||||
* sending CARD_STATE command with "halt" bit set.
|
||||
* 3: CT_KILL_EXIT
|
||||
* Host sets this to request exit from CT_KILL state, i.e. host thinks
|
||||
* device temperature is low enough to continue normal operation.
|
||||
* 2: CMD_BLOCKED
|
||||
* Host sets this during RF KILL power-down sequence (HW, SW, CT KILL)
|
||||
* to release uCode to clear all Tx and command queues, enter
|
||||
* unassociated mode, and power down.
|
||||
* NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit.
|
||||
* 1: SW_BIT_RFKILL
|
||||
* Host sets this when issuing CARD_STATE command to request
|
||||
* device sleep.
|
||||
* 0: MAC_SLEEP
|
||||
* uCode sets this when preparing a power-saving power-down.
|
||||
* uCode resets this when power-up is complete and SRAM is sane.
|
||||
* NOTE: 3945/4965 saves internal SRAM data to host when powering down,
|
||||
* and must restore this data after powering back up.
|
||||
* MAC_SLEEP is the best indication that restore is complete.
|
||||
* Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
|
||||
* do not need to save/restore it.
|
||||
*/
|
||||
#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
|
||||
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
|
||||
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
|
||||
|
@ -265,7 +373,7 @@
|
|||
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
|
||||
|
||||
|
||||
/* GI Chicken Bits */
|
||||
/* GIO Chicken Bits (PCI Express bus link power management) */
|
||||
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
|
||||
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
|
||||
|
||||
|
@ -285,8 +393,23 @@
|
|||
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
|
||||
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
|
||||
|
||||
/*=== HBUS (Host-side Bus) ===*/
|
||||
/*
|
||||
* HBUS (Host-side Bus)
|
||||
*
|
||||
* HBUS registers are mapped directly into PCI bus space, but are used
|
||||
* to indirectly access device's internal memory or registers that
|
||||
* may be powered-down.
|
||||
*
|
||||
* Use iwl_write_direct32()/iwl_read_direct32() family for these registers;
|
||||
* host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ
|
||||
* to make sure the MAC (uCode processor, etc.) is powered up for accessing
|
||||
* internal resources.
|
||||
*
|
||||
* Do not use iwl_write32()/iwl_read32() family to access these registers;
|
||||
* these provide only simple PCI bus access, without waking up the MAC.
|
||||
*/
|
||||
#define HBUS_BASE (0x400)
|
||||
|
||||
/*
|
||||
* Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
|
||||
* structures, error log, event log, verifying uCode load).
|
||||
|
@ -301,6 +424,10 @@
|
|||
#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
|
||||
#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
|
||||
|
||||
/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */
|
||||
#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
|
||||
#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
|
||||
|
||||
/*
|
||||
* Registers for accessing device's internal peripheral registers
|
||||
* (e.g. SCD, BSM, etc.). First write to address register,
|
||||
|
@ -315,16 +442,12 @@
|
|||
#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
|
||||
|
||||
/*
|
||||
* Per-Tx-queue write pointer (index, really!) (3945 and 4965).
|
||||
* Per-Tx-queue write pointer (index, really!)
|
||||
* Indicates index to next TFD that driver will fill (1 past latest filled).
|
||||
* Bit usage:
|
||||
* 0-7: queue write index
|
||||
* 11-8: queue selector
|
||||
*/
|
||||
#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
|
||||
#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
|
||||
|
||||
#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
|
||||
|
||||
|
||||
#endif /* !__iwl_csr_h__ */
|
||||
|
|
|
@ -107,6 +107,8 @@ struct iwl_debugfs {
|
|||
struct dentry *file_chain_noise;
|
||||
struct dentry *file_tx_power;
|
||||
struct dentry *file_power_save_status;
|
||||
struct dentry *file_clear_ucode_statistics;
|
||||
struct dentry *file_clear_traffic_statistics;
|
||||
} dbgfs_debug_files;
|
||||
u32 sram_offset;
|
||||
u32 sram_len;
|
||||
|
|
|
@ -47,9 +47,9 @@
|
|||
goto err; \
|
||||
} while (0)
|
||||
|
||||
#define DEBUGFS_ADD_FILE(name, parent) do { \
|
||||
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
|
||||
dbgfs->dbgfs_##parent##_files.file_##name = \
|
||||
debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
|
||||
debugfs_create_file(#name, mode, \
|
||||
dbgfs->dir_##parent, priv, \
|
||||
&iwl_dbgfs_##name##_ops); \
|
||||
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
|
||||
|
@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
|||
|
||||
int cnt;
|
||||
ssize_t ret;
|
||||
const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
|
||||
const size_t bufsz = 100 +
|
||||
sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
|
||||
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%s\t\t: %u\n",
|
||||
"\t%25s\t\t: %u\n",
|
||||
get_mgmt_string(cnt),
|
||||
priv->tx_stats.mgmt[cnt]);
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
|
||||
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%s\t\t: %u\n",
|
||||
"\t%25s\t\t: %u\n",
|
||||
get_ctrl_string(cnt),
|
||||
priv->tx_stats.ctrl[cnt]);
|
||||
}
|
||||
|
@ -159,7 +160,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
|
||||
static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -174,8 +175,7 @@ static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
|
|||
return -EFAULT;
|
||||
if (sscanf(buf, "%x", &clear_flag) != 1)
|
||||
return -EFAULT;
|
||||
if (clear_flag == 1)
|
||||
iwl_clear_tx_stats(priv);
|
||||
iwl_clear_traffic_stats(priv);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
|||
int cnt;
|
||||
ssize_t ret;
|
||||
const size_t bufsz = 100 +
|
||||
sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
|
||||
sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
@ -198,14 +198,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
|||
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
|
||||
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%s\t\t: %u\n",
|
||||
"\t%25s\t\t: %u\n",
|
||||
get_mgmt_string(cnt),
|
||||
priv->rx_stats.mgmt[cnt]);
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
|
||||
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%s\t\t: %u\n",
|
||||
"\t%25s\t\t: %u\n",
|
||||
get_ctrl_string(cnt),
|
||||
priv->rx_stats.ctrl[cnt]);
|
||||
}
|
||||
|
@ -220,26 +220,6 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
u32 clear_flag;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%x", &clear_flag) != 1)
|
||||
return -EFAULT;
|
||||
if (clear_flag == 1)
|
||||
iwl_clear_rx_stats(priv);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define BYTE1_MASK 0x000000ff;
|
||||
#define BYTE2_MASK 0x0000ffff;
|
||||
#define BYTE3_MASK 0x00ffffff;
|
||||
|
@ -248,13 +228,29 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u32 val;
|
||||
char buf[1024];
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
int pos = 0;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
||||
const size_t bufsz = sizeof(buf);
|
||||
size_t bufsz;
|
||||
|
||||
/* default is to dump the entire data segment */
|
||||
if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) {
|
||||
priv->dbgfs->sram_offset = 0x800000;
|
||||
if (priv->ucode_type == UCODE_INIT)
|
||||
priv->dbgfs->sram_len = priv->ucode_init_data.len;
|
||||
else
|
||||
priv->dbgfs->sram_len = priv->ucode_data.len;
|
||||
}
|
||||
bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10;
|
||||
buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
|
||||
priv->dbgfs->sram_len);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
|
||||
priv->dbgfs->sram_offset);
|
||||
for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
|
||||
val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
|
||||
priv->dbgfs->sram_len - i);
|
||||
|
@ -271,11 +267,14 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!(i % 16))
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
|
||||
}
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -335,8 +334,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
|
|||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"flags: 0x%x\n",
|
||||
station->sta.station_flags_msk);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"ps_status: %u\n", station->ps_status);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"seq_num\t\ttxq_id");
|
||||
|
@ -439,7 +436,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
|
|||
if (sscanf(buf, "%d", &event_log_flag) != 1)
|
||||
return -EFAULT;
|
||||
if (event_log_flag == 1)
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv);
|
||||
priv->cfg->ops->lib->dump_nic_event_log(priv, true);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -986,7 +983,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
|||
int pos = 0;
|
||||
int cnt;
|
||||
int ret;
|
||||
const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues;
|
||||
const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
|
||||
|
||||
if (!priv->txq) {
|
||||
IWL_ERR(priv, "txq not ready\n");
|
||||
|
@ -1042,10 +1039,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
|
|||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
|
||||
#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
|
||||
#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2)
|
||||
|
||||
static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
|
||||
int bufsz)
|
||||
{
|
||||
|
@ -1092,7 +1085,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
|
|||
|
||||
/* make request to uCode to retrieve statistics information */
|
||||
mutex_lock(&priv->mutex);
|
||||
ret = iwl_send_statistics_request(priv, 0);
|
||||
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (ret) {
|
||||
|
@ -1398,7 +1391,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
|
|||
|
||||
/* make request to uCode to retrieve statistics information */
|
||||
mutex_lock(&priv->mutex);
|
||||
ret = iwl_send_statistics_request(priv, 0);
|
||||
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (ret) {
|
||||
|
@ -1542,7 +1535,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
|
|||
|
||||
/* make request to uCode to retrieve statistics information */
|
||||
mutex_lock(&priv->mutex);
|
||||
ret = iwl_send_statistics_request(priv, 0);
|
||||
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (ret) {
|
||||
|
@ -1770,7 +1763,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
|
|||
else {
|
||||
/* make request to uCode to retrieve statistics information */
|
||||
mutex_lock(&priv->mutex);
|
||||
ret = iwl_send_statistics_request(priv, 0);
|
||||
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (ret) {
|
||||
|
@ -1828,8 +1821,32 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
|
|||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
|
||||
static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_priv *priv = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int clear;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &clear) != 1)
|
||||
return -EFAULT;
|
||||
|
||||
/* make request to uCode to retrieve statistics information */
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl_send_statistics_request(priv, CMD_SYNC, true);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DEBUGFS_READ_FILE_OPS(rx_statistics);
|
||||
DEBUGFS_READ_FILE_OPS(tx_statistics);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
|
||||
DEBUGFS_READ_FILE_OPS(rx_queue);
|
||||
DEBUGFS_READ_FILE_OPS(tx_queue);
|
||||
|
@ -1840,6 +1857,8 @@ DEBUGFS_READ_FILE_OPS(sensitivity);
|
|||
DEBUGFS_READ_FILE_OPS(chain_noise);
|
||||
DEBUGFS_READ_FILE_OPS(tx_power);
|
||||
DEBUGFS_READ_FILE_OPS(power_save_status);
|
||||
DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
|
||||
DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
|
||||
|
||||
/*
|
||||
* Create the debugfs files and directories
|
||||
|
@ -1868,32 +1887,34 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
|
|||
DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
|
||||
DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
|
||||
DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
|
||||
DEBUGFS_ADD_FILE(nvm, data);
|
||||
DEBUGFS_ADD_FILE(sram, data);
|
||||
DEBUGFS_ADD_FILE(log_event, data);
|
||||
DEBUGFS_ADD_FILE(stations, data);
|
||||
DEBUGFS_ADD_FILE(channels, data);
|
||||
DEBUGFS_ADD_FILE(status, data);
|
||||
DEBUGFS_ADD_FILE(interrupt, data);
|
||||
DEBUGFS_ADD_FILE(qos, data);
|
||||
DEBUGFS_ADD_FILE(led, data);
|
||||
DEBUGFS_ADD_FILE(sleep_level_override, data);
|
||||
DEBUGFS_ADD_FILE(current_sleep_command, data);
|
||||
DEBUGFS_ADD_FILE(thermal_throttling, data);
|
||||
DEBUGFS_ADD_FILE(disable_ht40, data);
|
||||
DEBUGFS_ADD_FILE(rx_statistics, debug);
|
||||
DEBUGFS_ADD_FILE(tx_statistics, debug);
|
||||
DEBUGFS_ADD_FILE(traffic_log, debug);
|
||||
DEBUGFS_ADD_FILE(rx_queue, debug);
|
||||
DEBUGFS_ADD_FILE(tx_queue, debug);
|
||||
DEBUGFS_ADD_FILE(tx_power, debug);
|
||||
DEBUGFS_ADD_FILE(power_save_status, debug);
|
||||
DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(status, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(qos, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(led, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
|
||||
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
|
||||
DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
|
||||
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
|
||||
DEBUGFS_ADD_FILE(ucode_general_stats, debug);
|
||||
DEBUGFS_ADD_FILE(sensitivity, debug);
|
||||
DEBUGFS_ADD_FILE(chain_noise, debug);
|
||||
DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
|
||||
}
|
||||
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
|
||||
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
|
||||
|
@ -1941,6 +1962,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
|||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_clear_ucode_statistics);
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_clear_traffic_statistics);
|
||||
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
|
||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||
file_ucode_rx_stats);
|
||||
|
|
|
@ -52,19 +52,16 @@ extern struct iwl_cfg iwl4965_agn_cfg;
|
|||
extern struct iwl_cfg iwl5300_agn_cfg;
|
||||
extern struct iwl_cfg iwl5100_agn_cfg;
|
||||
extern struct iwl_cfg iwl5350_agn_cfg;
|
||||
extern struct iwl_cfg iwl5100_bg_cfg;
|
||||
extern struct iwl_cfg iwl5100_bgn_cfg;
|
||||
extern struct iwl_cfg iwl5100_abg_cfg;
|
||||
extern struct iwl_cfg iwl5150_agn_cfg;
|
||||
extern struct iwl_cfg iwl6000h_2agn_cfg;
|
||||
extern struct iwl_cfg iwl6000h_2abg_cfg;
|
||||
extern struct iwl_cfg iwl6000h_2bg_cfg;
|
||||
extern struct iwl_cfg iwl5150_abg_cfg;
|
||||
extern struct iwl_cfg iwl6000i_2agn_cfg;
|
||||
extern struct iwl_cfg iwl6000i_2abg_cfg;
|
||||
extern struct iwl_cfg iwl6000i_2bg_cfg;
|
||||
extern struct iwl_cfg iwl6000_3agn_cfg;
|
||||
extern struct iwl_cfg iwl6050_2agn_cfg;
|
||||
extern struct iwl_cfg iwl6050_2abg_cfg;
|
||||
extern struct iwl_cfg iwl6050_3agn_cfg;
|
||||
extern struct iwl_cfg iwl1000_bgn_cfg;
|
||||
extern struct iwl_cfg iwl1000_bg_cfg;
|
||||
|
||||
|
@ -295,9 +292,6 @@ struct iwl_channel_info {
|
|||
|
||||
/* HT40 channel info */
|
||||
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
||||
s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
|
||||
s8 ht40_min_power; /* always 0 */
|
||||
s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */
|
||||
u8 ht40_flags; /* flags copied from EEPROM */
|
||||
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
||||
|
||||
|
@ -518,7 +512,6 @@ struct iwl_ht_config {
|
|||
bool is_ht;
|
||||
bool is_40mhz;
|
||||
bool single_chain_sufficient;
|
||||
u8 sm_ps;
|
||||
/* BSS related data */
|
||||
u8 extension_chan_offset;
|
||||
u8 ht_protection;
|
||||
|
@ -552,23 +545,10 @@ struct iwl_qos_info {
|
|||
struct iwl_qosparam_cmd def_qos_parm;
|
||||
};
|
||||
|
||||
#define STA_PS_STATUS_WAKE 0
|
||||
#define STA_PS_STATUS_SLEEP 1
|
||||
|
||||
|
||||
struct iwl3945_station_entry {
|
||||
struct iwl3945_addsta_cmd sta;
|
||||
struct iwl_tid_data tid[MAX_TID_COUNT];
|
||||
u8 used;
|
||||
u8 ps_status;
|
||||
struct iwl_hw_key keyinfo;
|
||||
};
|
||||
|
||||
struct iwl_station_entry {
|
||||
struct iwl_addsta_cmd sta;
|
||||
struct iwl_tid_data tid[MAX_TID_COUNT];
|
||||
u8 used;
|
||||
u8 ps_status;
|
||||
struct iwl_hw_key keyinfo;
|
||||
};
|
||||
|
||||
|
@ -578,11 +558,12 @@ struct iwl_station_entry {
|
|||
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
|
||||
* in the structure for use by driver. This structure is places in that
|
||||
* space.
|
||||
*
|
||||
* At the moment use it for the station's rate scaling information.
|
||||
*/
|
||||
struct iwl_station_priv {
|
||||
struct iwl_lq_sta lq_sta;
|
||||
atomic_t pending_frames;
|
||||
bool client;
|
||||
bool asleep;
|
||||
};
|
||||
|
||||
/* one for each uCode image (inst/data, boot/init/runtime) */
|
||||
|
@ -1254,6 +1235,7 @@ struct iwl_priv {
|
|||
/* TX Power */
|
||||
s8 tx_power_user_lmt;
|
||||
s8 tx_power_device_lmt;
|
||||
s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
|
||||
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define CREATE_TRACE_POINTS
|
||||
#include "iwl-devtrace.h"
|
||||
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
|
||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
|
||||
|
|
|
@ -14,7 +14,7 @@ static inline void trace_ ## name(proto) {}
|
|||
#define PRIV_ASSIGN __entry->priv = priv
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi
|
||||
#define TRACE_SYSTEM iwlwifi_io
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_ioread32,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
||||
|
@ -32,6 +32,22 @@ TRACE_EVENT(iwlwifi_dev_ioread32,
|
|||
TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_iowrite8,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
|
||||
TP_ARGS(priv, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
PRIV_ENTRY
|
||||
__field(u32, offs)
|
||||
__field(u8, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
PRIV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_iowrite32,
|
||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
||||
TP_ARGS(priv, offs, val),
|
||||
|
@ -48,6 +64,9 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
|
|||
TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM iwlwifi
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_hcmd,
|
||||
TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
|
||||
TP_ARGS(priv, hcmd, len, flags),
|
||||
|
|
|
@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv)
|
|||
}
|
||||
e = (u16 *)priv->eeprom;
|
||||
|
||||
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
|
||||
/* OTP reads require powered-up chip */
|
||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
||||
}
|
||||
|
||||
ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
|
||||
|
@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
|
|||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
|
||||
|
||||
/* OTP reads require powered-up chip */
|
||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
||||
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
|
||||
|
||||
ret = iwl_init_otp_access(priv);
|
||||
if (ret) {
|
||||
|
@ -751,9 +754,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
|
|||
|
||||
ch_info->ht40_eeprom = *eeprom_ch;
|
||||
ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_min_power = 0;
|
||||
ch_info->ht40_scan_power = eeprom_ch->max_power_avg;
|
||||
ch_info->ht40_flags = eeprom_ch->flags;
|
||||
ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
|
||||
|
||||
|
@ -765,7 +765,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
|
|||
* find the highest tx power from all chains for the channel
|
||||
*/
|
||||
static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
|
||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element)
|
||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
|
||||
int element, s8 *max_txpower_in_half_dbm)
|
||||
{
|
||||
s8 max_txpower_avg = 0; /* (dBm) */
|
||||
|
||||
|
@ -797,10 +798,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
|
|||
(enhanced_txpower[element].mimo3_max > max_txpower_avg))
|
||||
max_txpower_avg = enhanced_txpower[element].mimo3_max;
|
||||
|
||||
/* max. tx power in EEPROM is in 1/2 dBm format
|
||||
* convert from 1/2 dBm to dBm
|
||||
/*
|
||||
* max. tx power in EEPROM is in 1/2 dBm format
|
||||
* convert from 1/2 dBm to dBm (round-up convert)
|
||||
* but we also do not want to loss 1/2 dBm resolution which
|
||||
* will impact performance
|
||||
*/
|
||||
return max_txpower_avg >> 1;
|
||||
*max_txpower_in_half_dbm = max_txpower_avg;
|
||||
return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -809,7 +814,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
|
|||
*/
|
||||
static s8 iwl_update_common_txpower(struct iwl_priv *priv,
|
||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
|
||||
int section, int element)
|
||||
int section, int element, s8 *max_txpower_in_half_dbm)
|
||||
{
|
||||
struct iwl_channel_info *ch_info;
|
||||
int ch;
|
||||
|
@ -823,25 +828,25 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
|
|||
if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
|
||||
is_ht40 = true;
|
||||
max_txpower_avg =
|
||||
iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
|
||||
iwl_get_max_txpower_avg(priv, enhanced_txpower,
|
||||
element, max_txpower_in_half_dbm);
|
||||
|
||||
ch_info = priv->channel_info;
|
||||
|
||||
for (ch = 0; ch < priv->channel_count; ch++) {
|
||||
/* find matching band and update tx power if needed */
|
||||
if ((ch_info->band == enhinfo[section].band) &&
|
||||
(ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) {
|
||||
(ch_info->max_power_avg < max_txpower_avg) &&
|
||||
(!is_ht40)) {
|
||||
/* Update regulatory-based run-time data */
|
||||
ch_info->max_power_avg = ch_info->curr_txpow =
|
||||
max_txpower_avg;
|
||||
max_txpower_avg;
|
||||
ch_info->scan_power = max_txpower_avg;
|
||||
}
|
||||
if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
|
||||
ch_info->ht40_max_power_avg &&
|
||||
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
||||
/* Update regulatory-based run-time data */
|
||||
ch_info->ht40_max_power_avg = max_txpower_avg;
|
||||
ch_info->ht40_curr_txpow = max_txpower_avg;
|
||||
ch_info->ht40_scan_power = max_txpower_avg;
|
||||
}
|
||||
ch_info++;
|
||||
}
|
||||
|
@ -854,7 +859,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
|
|||
*/
|
||||
static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
|
||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
|
||||
int section, int element)
|
||||
int section, int element, s8 *max_txpower_in_half_dbm)
|
||||
{
|
||||
struct iwl_channel_info *ch_info;
|
||||
int ch;
|
||||
|
@ -863,7 +868,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
|
|||
|
||||
channel = enhinfo[section].iwl_eeprom_section_channel[element];
|
||||
max_txpower_avg =
|
||||
iwl_get_max_txpower_avg(priv, enhanced_txpower, element);
|
||||
iwl_get_max_txpower_avg(priv, enhanced_txpower,
|
||||
element, max_txpower_in_half_dbm);
|
||||
|
||||
ch_info = priv->channel_info;
|
||||
for (ch = 0; ch < priv->channel_count; ch++) {
|
||||
|
@ -877,12 +883,9 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
|
|||
ch_info->scan_power = max_txpower_avg;
|
||||
}
|
||||
if ((enhinfo[section].is_ht40) &&
|
||||
(ch_info->ht40_max_power_avg) &&
|
||||
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
||||
/* Update regulatory-based run-time data */
|
||||
ch_info->ht40_max_power_avg = max_txpower_avg;
|
||||
ch_info->ht40_curr_txpow = max_txpower_avg;
|
||||
ch_info->ht40_scan_power = max_txpower_avg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -901,6 +904,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
|
|||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
|
||||
u32 offset;
|
||||
s8 max_txpower_avg; /* (dBm) */
|
||||
s8 max_txpower_in_half_dbm; /* (half-dBm) */
|
||||
|
||||
/* Loop through all the sections
|
||||
* adjust bands and channel's max tx power
|
||||
|
@ -913,20 +917,43 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
|
|||
enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
|
||||
iwl_eeprom_query_addr(priv, offset);
|
||||
|
||||
/*
|
||||
* check for valid entry -
|
||||
* different version of EEPROM might contain different set
|
||||
* of enhanced tx power table
|
||||
* always check for valid entry before process
|
||||
* the information
|
||||
*/
|
||||
if (!enhanced_txpower->common || enhanced_txpower->reserved)
|
||||
continue;
|
||||
|
||||
for (element = 0; element < eeprom_section_count; element++) {
|
||||
if (enhinfo[section].is_common)
|
||||
max_txpower_avg =
|
||||
iwl_update_common_txpower(priv,
|
||||
enhanced_txpower, section, element);
|
||||
enhanced_txpower, section,
|
||||
element,
|
||||
&max_txpower_in_half_dbm);
|
||||
else
|
||||
max_txpower_avg =
|
||||
iwl_update_channel_txpower(priv,
|
||||
enhanced_txpower, section, element);
|
||||
enhanced_txpower, section,
|
||||
element,
|
||||
&max_txpower_in_half_dbm);
|
||||
|
||||
/* Update the tx_power_user_lmt to the highest power
|
||||
* supported by any channel */
|
||||
if (max_txpower_avg > priv->tx_power_user_lmt)
|
||||
priv->tx_power_user_lmt = max_txpower_avg;
|
||||
|
||||
/*
|
||||
* Update the tx_power_lmt_in_half_dbm to
|
||||
* the highest power supported by any channel
|
||||
*/
|
||||
if (max_txpower_in_half_dbm >
|
||||
priv->tx_power_lmt_in_half_dbm)
|
||||
priv->tx_power_lmt_in_half_dbm =
|
||||
max_txpower_in_half_dbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,19 +127,21 @@ struct iwl_eeprom_channel {
|
|||
* Enhanced regulatory tx power portion of eeprom image can be broken down
|
||||
* into individual structures; each one is 8 bytes in size and contain the
|
||||
* following information
|
||||
* @common: (desc + channel) not used by driver, should _NOT_ be "zero"
|
||||
* @chain_a_max_pwr: chain a max power in 1/2 dBm
|
||||
* @chain_b_max_pwr: chain b max power in 1/2 dBm
|
||||
* @chain_c_max_pwr: chain c max power in 1/2 dBm
|
||||
* @reserved: not used, should be "zero"
|
||||
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
|
||||
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
|
||||
*
|
||||
*/
|
||||
struct iwl_eeprom_enhanced_txpwr {
|
||||
u16 reserved;
|
||||
u16 common;
|
||||
s8 chain_a_max;
|
||||
s8 chain_b_max;
|
||||
s8 chain_c_max;
|
||||
s8 reserved1;
|
||||
s8 reserved;
|
||||
s8 mimo2_max;
|
||||
s8 mimo3_max;
|
||||
} __attribute__ ((packed));
|
||||
|
|
|
@ -62,6 +62,26 @@
|
|||
*
|
||||
*/
|
||||
|
||||
static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
|
||||
{
|
||||
trace_iwlwifi_dev_iowrite8(priv, ofs, val);
|
||||
iowrite8(val, priv->hw_base + ofs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv,
|
||||
u32 ofs, u8 val)
|
||||
{
|
||||
IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l);
|
||||
_iwl_write8(priv, ofs, val);
|
||||
}
|
||||
#define iwl_write8(priv, ofs, val) \
|
||||
__iwl_write8(__FILE__, __LINE__, priv, ofs, val)
|
||||
#else
|
||||
#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val)
|
||||
#endif
|
||||
|
||||
|
||||
static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
|
||||
{
|
||||
trace_iwlwifi_dev_iowrite32(priv, ofs, val);
|
||||
|
|
|
@ -219,7 +219,6 @@ EXPORT_SYMBOL(iwl_leds_background);
|
|||
void iwl_leds_init(struct iwl_priv *priv)
|
||||
{
|
||||
priv->last_blink_rate = 0;
|
||||
priv->led_tpt = 0;
|
||||
priv->last_blink_time = 0;
|
||||
priv->allow_blinking = 0;
|
||||
}
|
||||
|
|
|
@ -506,7 +506,7 @@ static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
|
|||
{
|
||||
IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
|
||||
/* make request to retrieve statistics information */
|
||||
iwl_send_statistics_request(priv, 0);
|
||||
iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
/* Reschedule the ct_kill wait timer */
|
||||
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
|
||||
jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
|
||||
|
|
|
@ -477,7 +477,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
|||
(rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
|
||||
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
|
||||
|
||||
iwl_write32(priv, CSR_INT_COALESCING, 0x40);
|
||||
/* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
|
||||
iwl_write8(priv, CSR_INT_COALESCING, 0x40);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -635,6 +636,24 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_rx_statistics);
|
||||
|
||||
void iwl_reply_statistics(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
|
||||
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
|
||||
memset(&priv->statistics, 0,
|
||||
sizeof(struct iwl_notif_statistics));
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
memset(&priv->accum_statistics, 0,
|
||||
sizeof(struct iwl_notif_statistics));
|
||||
#endif
|
||||
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
|
||||
}
|
||||
iwl_rx_statistics(priv, rxb);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_reply_statistics);
|
||||
|
||||
#define PERFECT_RSSI (-20) /* dBm */
|
||||
#define WORST_RSSI (-95) /* dBm */
|
||||
#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
|
||||
|
@ -1010,7 +1029,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
|
|||
struct iwl4965_rx_mpdu_res_start *amsdu;
|
||||
u32 len;
|
||||
u32 ampdu_status;
|
||||
u16 fc;
|
||||
u32 rate_n_flags;
|
||||
|
||||
/**
|
||||
|
@ -1143,20 +1161,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
|
|||
priv->last_tsf = le64_to_cpu(phy_res->timestamp);
|
||||
}
|
||||
|
||||
fc = le16_to_cpu(header->frame_control);
|
||||
switch (fc & IEEE80211_FCTL_FTYPE) {
|
||||
case IEEE80211_FTYPE_MGMT:
|
||||
case IEEE80211_FTYPE_DATA:
|
||||
if (priv->iw_mode == NL80211_IFTYPE_AP)
|
||||
iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
|
||||
header->addr2);
|
||||
/* fall through */
|
||||
default:
|
||||
iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
|
||||
rxb, &rx_status);
|
||||
break;
|
||||
|
||||
}
|
||||
iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
|
||||
rxb, &rx_status);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_rx_reply_rx);
|
||||
|
||||
|
|
|
@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
|
||||
|
||||
static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
|
||||
void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
|
|||
priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.sta.modify_mask = 0;
|
||||
priv->stations[sta_id].sta.sleep_tx_count = 0;
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
|
||||
|
||||
void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
|
||||
void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
|
||||
{
|
||||
/* FIXME: need locking over ps_status ??? */
|
||||
u8 sta_id = iwl_find_station(priv, addr);
|
||||
unsigned long flags;
|
||||
|
||||
if (sta_id != IWL_INVALID_STATION) {
|
||||
u8 sta_awake = priv->stations[sta_id].
|
||||
ps_status == STA_PS_STATUS_WAKE;
|
||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||
priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
|
||||
priv->stations[sta_id].sta.sta.modify_mask =
|
||||
STA_MODIFY_SLEEP_TX_COUNT_MSK;
|
||||
priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
|
||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||
|
||||
if (sta_awake && ps_bit)
|
||||
priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
|
||||
else if (!sta_awake && !ps_bit) {
|
||||
iwl_sta_modify_ps_wake(priv, sta_id);
|
||||
priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
|
||||
}
|
||||
}
|
||||
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,5 +66,6 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
|
|||
int iwl_sta_rx_agg_start(struct iwl_priv *priv,
|
||||
const u8 *addr, int tid, u16 ssn);
|
||||
int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
|
||||
void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
|
||||
void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
|
||||
void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
|
||||
#endif /* __iwl_sta_h__ */
|
||||
|
|
|
@ -710,6 +710,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sta *sta = info->control.sta;
|
||||
struct iwl_station_priv *sta_priv = NULL;
|
||||
struct iwl_tx_queue *txq;
|
||||
struct iwl_queue *q;
|
||||
struct iwl_device_cmd *out_cmd;
|
||||
|
@ -772,6 +774,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
|
||||
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
|
||||
|
||||
if (sta)
|
||||
sta_priv = (void *)sta->drv_priv;
|
||||
|
||||
if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
|
||||
sta_priv->asleep) {
|
||||
WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
|
||||
/*
|
||||
* This sends an asynchronous command to the device,
|
||||
* but we can rely on it being processed before the
|
||||
* next frame is processed -- and the next frame to
|
||||
* this station is the one that will consume this
|
||||
* counter.
|
||||
* For now set the counter to just 1 since we do not
|
||||
* support uAPSD yet.
|
||||
*/
|
||||
iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
|
||||
}
|
||||
|
||||
txq_id = skb_get_queue_mapping(skb);
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
|
@ -931,6 +951,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
ret = iwl_txq_update_write_ptr(priv, txq);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/*
|
||||
* At this point the frame is "transmitted" successfully
|
||||
* and we will get a TX status notification eventually,
|
||||
* regardless of the value of ret. "ret" only indicates
|
||||
* whether or not we should update the write pointer.
|
||||
*/
|
||||
|
||||
/* avoid atomic ops if it isn't an associated client */
|
||||
if (sta_priv && sta_priv->client)
|
||||
atomic_inc(&sta_priv->pending_frames);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -992,7 +1023,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
}
|
||||
|
||||
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
|
||||
IWL_ERR(priv, "No space for Tx\n");
|
||||
IWL_ERR(priv, "No space in command queue\n");
|
||||
if (iwl_within_ct_kill_margin(priv))
|
||||
iwl_tt_enter_ct_kill(priv);
|
||||
else {
|
||||
|
@ -1075,6 +1106,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
return ret ? ret : idx;
|
||||
}
|
||||
|
||||
static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_station_priv *sta_priv;
|
||||
|
||||
sta = ieee80211_find_sta(priv->vif, hdr->addr1);
|
||||
if (sta) {
|
||||
sta_priv = (void *)sta->drv_priv;
|
||||
/* avoid atomic ops if this isn't a client */
|
||||
if (sta_priv->client &&
|
||||
atomic_dec_return(&sta_priv->pending_frames) == 0)
|
||||
ieee80211_sta_block_awake(priv->hw, sta, false);
|
||||
}
|
||||
|
||||
ieee80211_tx_status_irqsafe(priv->hw, skb);
|
||||
}
|
||||
|
||||
int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
|
||||
{
|
||||
struct iwl_tx_queue *txq = &priv->txq[txq_id];
|
||||
|
@ -1094,7 +1143,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
|
|||
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||
|
||||
tx_info = &txq->txb[txq->q.read_ptr];
|
||||
ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
|
||||
iwl_tx_status(priv, tx_info->skb[0]);
|
||||
tx_info->skb[0] = NULL;
|
||||
|
||||
if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
|
||||
|
@ -1264,7 +1313,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
|
|||
if (tid_data->tfds_in_queue == 0) {
|
||||
IWL_DEBUG_HT(priv, "HW queue is empty\n");
|
||||
tid_data->agg.state = IWL_AGG_ON;
|
||||
ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
|
||||
} else {
|
||||
IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
|
||||
tid_data->tfds_in_queue);
|
||||
|
@ -1329,7 +1378,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1353,7 +1402,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
|
|||
priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
|
||||
ssn, tx_fifo);
|
||||
tid_data->agg.state = IWL_AGG_OFF;
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
|
||||
}
|
||||
break;
|
||||
case IWL_EMPTYING_HW_QUEUE_ADDBA:
|
||||
|
@ -1361,7 +1410,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
|
|||
if (tid_data->tfds_in_queue == 0) {
|
||||
IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
|
||||
tid_data->agg.state = IWL_AGG_ON;
|
||||
ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1483,7 +1483,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
|
|||
tasklet_kill(&priv->irq_tasklet);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static const char *desc_lookup(int i)
|
||||
{
|
||||
switch (i) {
|
||||
|
@ -1614,10 +1613,42 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
|||
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
|
||||
*/
|
||||
static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
|
||||
u32 num_wraps, u32 next_entry,
|
||||
u32 size, u32 mode)
|
||||
{
|
||||
/*
|
||||
* display the newest DEFAULT_LOG_ENTRIES entries
|
||||
* i.e the entries just before the next ont that uCode would fill.
|
||||
*/
|
||||
if (num_wraps) {
|
||||
if (next_entry < size) {
|
||||
iwl3945_print_event_log(priv,
|
||||
capacity - (size - next_entry),
|
||||
size - next_entry, mode);
|
||||
iwl3945_print_event_log(priv, 0,
|
||||
next_entry, mode);
|
||||
} else
|
||||
iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
} else {
|
||||
if (next_entry < size)
|
||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
||||
else
|
||||
iwl3945_print_event_log(priv, next_entry - size,
|
||||
size, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||
#define IWL3945_MAX_EVENT_LOG_SIZE (512)
|
||||
|
||||
void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
||||
#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
|
||||
|
||||
void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
|
||||
{
|
||||
u32 base; /* SRAM byte address of event log header */
|
||||
u32 capacity; /* event log capacity in # entries */
|
||||
|
@ -1658,8 +1689,17 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
|||
return;
|
||||
}
|
||||
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
|
||||
size, num_wraps);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS))
|
||||
size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES)
|
||||
? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size;
|
||||
#else
|
||||
size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES)
|
||||
? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size;
|
||||
#endif
|
||||
|
||||
IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n",
|
||||
size);
|
||||
|
||||
/* if uCode has wrapped back to top of log, start at the oldest entry,
|
||||
* i.e the next one that uCode would fill. */
|
||||
|
@ -1670,18 +1710,28 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
|||
/* (then/else) start at top of log */
|
||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
||||
|
||||
}
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
|
||||
/* if uCode has wrapped back to top of log,
|
||||
* start at the oldest entry,
|
||||
* i.e the next one that uCode would fill.
|
||||
*/
|
||||
if (num_wraps)
|
||||
iwl3945_print_event_log(priv, next_entry,
|
||||
capacity - next_entry, mode);
|
||||
|
||||
/* (then/else) start at top of log */
|
||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
||||
} else
|
||||
iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
#else
|
||||
void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
|
||||
void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
|
||||
{
|
||||
}
|
||||
|
||||
iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||
next_entry, size, mode);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
||||
{
|
||||
u32 inta, handled = 0;
|
||||
|
@ -2494,7 +2544,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
|
|||
priv->active_rate = priv->rates_mask;
|
||||
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
|
||||
|
||||
iwl_power_update_mode(priv, false);
|
||||
iwl_power_update_mode(priv, true);
|
||||
|
||||
if (iwl_is_associated(priv)) {
|
||||
struct iwl3945_rxon_cmd *active_rxon =
|
||||
|
@ -3650,7 +3700,7 @@ static ssize_t show_statistics(struct device *d,
|
|||
return -EAGAIN;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
rc = iwl_send_statistics_request(priv, 0);
|
||||
rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
if (rc) {
|
||||
|
@ -3905,10 +3955,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
|
|||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
|
||||
/* Firmware does not support this */
|
||||
hw->wiphy->disable_beacon_hints = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||
|
||||
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
|
||||
/* we create the 802.11 header and a zero-length SSID element */
|
||||
|
|
|
@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void)
|
|||
break;
|
||||
case HWSIM_REGTEST_WORLD_ROAM:
|
||||
if (i == 0) {
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_01);
|
||||
}
|
||||
break;
|
||||
case HWSIM_REGTEST_CUSTOM_WORLD:
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_01);
|
||||
break;
|
||||
case HWSIM_REGTEST_CUSTOM_WORLD_2:
|
||||
if (i == 0) {
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_01);
|
||||
} else if (i == 1) {
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_02);
|
||||
}
|
||||
break;
|
||||
case HWSIM_REGTEST_STRICT_ALL:
|
||||
hw->wiphy->strict_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||
break;
|
||||
case HWSIM_REGTEST_STRICT_FOLLOW:
|
||||
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
|
||||
if (i == 0)
|
||||
hw->wiphy->strict_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||
break;
|
||||
case HWSIM_REGTEST_ALL:
|
||||
if (i == 0) {
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_01);
|
||||
} else if (i == 1) {
|
||||
hw->wiphy->custom_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||
&hwsim_world_regdom_custom_02);
|
||||
} else if (i == 4)
|
||||
hw->wiphy->strict_regulatory = true;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|||
* For now, disable PS by default because it affects
|
||||
* link stability significantly.
|
||||
*/
|
||||
dev->wiphy->ps_default = false;
|
||||
dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
mutex_init(&priv->conf_mutex);
|
||||
mutex_init(&priv->eeprom_mutex);
|
||||
|
|
|
@ -83,11 +83,11 @@ MODULE_PARM_DESC(roamdelta,
|
|||
"set roaming tendency: 0=aggressive, 1=moderate, "
|
||||
"2=conservative (default: moderate)");
|
||||
|
||||
static int modparam_workaround_interval = 500;
|
||||
static int modparam_workaround_interval;
|
||||
module_param_named(workaround_interval, modparam_workaround_interval,
|
||||
int, 0444);
|
||||
MODULE_PARM_DESC(workaround_interval,
|
||||
"set stall workaround interval in msecs (default: 500)");
|
||||
"set stall workaround interval in msecs (0=disabled) (default: 0)");
|
||||
|
||||
|
||||
/* various RNDIS OID defs */
|
||||
|
@ -733,12 +733,13 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
|
|||
le32_to_cpu(u.get_c->status));
|
||||
|
||||
if (ret == 0) {
|
||||
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
|
||||
|
||||
ret = le32_to_cpu(u.get_c->len);
|
||||
if (ret > *len)
|
||||
*len = ret;
|
||||
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
|
||||
ret = rndis_error_status(u.get_c->status);
|
||||
|
||||
ret = rndis_error_status(u.get_c->status);
|
||||
if (ret < 0)
|
||||
devdbg(dev, "rndis_query_oid(%s): device returned "
|
||||
"error, 0x%08x (%d)", oid_to_string(oid),
|
||||
|
@ -2549,7 +2550,7 @@ static void rndis_device_poller(struct work_struct *work)
|
|||
/* Workaround transfer stalls on poor quality links.
|
||||
* TODO: find right way to fix these stalls (as stalls do not happen
|
||||
* with ndiswrapper/windows driver). */
|
||||
if (priv->last_qual <= 25) {
|
||||
if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) {
|
||||
/* Decrease stats worker interval to catch stalls.
|
||||
* faster. Faster than 400-500ms causes packet loss,
|
||||
* Slower doesn't catch stalls fast enough.
|
||||
|
|
|
@ -824,17 +824,23 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Amit */
|
||||
{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Askey */
|
||||
{ USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* ASUS */
|
||||
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* AzureWave */
|
||||
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Belkin */
|
||||
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -843,6 +849,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
/* Buffalo */
|
||||
{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Cisco */
|
||||
{ USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Conceptronic */
|
||||
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -858,6 +866,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* D-Link */
|
||||
|
@ -869,18 +879,24 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Edimax */
|
||||
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Encore */
|
||||
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* EnGenius */
|
||||
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Gemtek */
|
||||
{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -894,7 +910,10 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* I-O DATA */
|
||||
{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* LevelOne */
|
||||
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -909,8 +928,18 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
/* Motorola */
|
||||
{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* MSI */
|
||||
{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Ovislink */
|
||||
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Para */
|
||||
{ USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Pegatron */
|
||||
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -926,8 +955,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
/* Quanta */
|
||||
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Ralink */
|
||||
{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -951,7 +978,12 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* SMC */
|
||||
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
@ -960,6 +992,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Sparklan */
|
||||
|
@ -977,6 +1011,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
/* Zyxel */
|
||||
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||
|
|
|
@ -205,6 +205,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
|||
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
||||
unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
|
||||
u8 rate_idx, rate_flags, retry_rates;
|
||||
u8 skbdesc_flags = skbdesc->flags;
|
||||
unsigned int i;
|
||||
bool success;
|
||||
|
||||
|
@ -287,12 +288,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
|||
}
|
||||
|
||||
/*
|
||||
* Only send the status report to mac80211 when TX status was
|
||||
* requested by it. If this was a extra frame coming through
|
||||
* a mac80211 library call (RTS/CTS) then we should not send the
|
||||
* status report back.
|
||||
* Only send the status report to mac80211 when it's a frame
|
||||
* that originated in mac80211. If this was a extra frame coming
|
||||
* through a mac80211 library call (RTS/CTS) then we should not
|
||||
* send the status report back.
|
||||
*/
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
|
||||
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
|
||||
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
|
||||
else
|
||||
dev_kfree_skb_irq(entry->skb);
|
||||
|
|
|
@ -162,8 +162,10 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
|
|||
* rt2x00queue_write_tx_frame - Write TX frame to hardware
|
||||
* @queue: Queue over which the frame should be send
|
||||
* @skb: The skb to send
|
||||
* @local: frame is not from mac80211
|
||||
*/
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
|
||||
bool local);
|
||||
|
||||
/**
|
||||
* rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
|
||||
|
|
|
@ -66,7 +66,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
|
|||
rts_info = IEEE80211_SKB_CB(skb);
|
||||
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
|
||||
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
|
||||
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
||||
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
|
@ -91,7 +90,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
|
|||
frag_skb->data, data_length, tx_info,
|
||||
(struct ieee80211_rts *)(skb->data));
|
||||
|
||||
retval = rt2x00queue_write_tx_frame(queue, skb);
|
||||
retval = rt2x00queue_write_tx_frame(queue, skb, true);
|
||||
if (retval) {
|
||||
dev_kfree_skb_any(skb);
|
||||
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
|
||||
|
@ -153,7 +152,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
goto exit_fail;
|
||||
}
|
||||
|
||||
if (rt2x00queue_write_tx_frame(queue, skb))
|
||||
if (rt2x00queue_write_tx_frame(queue, skb, false))
|
||||
goto exit_fail;
|
||||
|
||||
if (rt2x00queue_threshold(queue))
|
||||
|
|
|
@ -454,7 +454,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
|
|||
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
|
||||
}
|
||||
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
||||
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
|
||||
bool local)
|
||||
{
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
|
||||
|
@ -495,6 +496,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
|
|||
skbdesc->tx_rate_idx = rate_idx;
|
||||
skbdesc->tx_rate_flags = rate_flags;
|
||||
|
||||
if (local)
|
||||
skbdesc->flags |= SKBDESC_NOT_MAC80211;
|
||||
|
||||
/*
|
||||
* When hardware encryption is supported, and this frame
|
||||
* is to be encrypted, we should strip the IV/EIV data from
|
||||
|
|
|
@ -94,12 +94,15 @@ enum data_queue_qid {
|
|||
* mac80211 but was stripped for processing by the driver.
|
||||
* @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
|
||||
* the padded bytes are located between header and payload.
|
||||
* @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
|
||||
* don't try to pass it back.
|
||||
*/
|
||||
enum skb_frame_desc_flags {
|
||||
SKBDESC_DMA_MAPPED_RX = 1 << 0,
|
||||
SKBDESC_DMA_MAPPED_TX = 1 << 1,
|
||||
SKBDESC_IV_STRIPPED = 1 << 2,
|
||||
SKBDESC_L2_PADDED = 1 << 3
|
||||
SKBDESC_L2_PADDED = 1 << 3,
|
||||
SKBDESC_NOT_MAC80211 = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -269,6 +269,7 @@ struct wl1251 {
|
|||
|
||||
void (*set_power)(bool enable);
|
||||
int irq;
|
||||
bool use_eeprom;
|
||||
|
||||
enum wl1251_state state;
|
||||
struct mutex mutex;
|
||||
|
@ -354,6 +355,8 @@ struct wl1251 {
|
|||
/* is firmware in elp mode */
|
||||
bool elp;
|
||||
|
||||
struct delayed_work elp_work;
|
||||
|
||||
/* we can be in psm, but not in elp, we have to differentiate */
|
||||
bool psm;
|
||||
|
||||
|
@ -374,6 +377,8 @@ struct wl1251 {
|
|||
u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
|
||||
struct wl1251_rx_descriptor *rx_descriptor;
|
||||
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
u32 chip_id;
|
||||
char fw_ver[21];
|
||||
};
|
||||
|
|
|
@ -494,7 +494,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
|
||||
int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter)
|
||||
{
|
||||
struct acx_beacon_filter_option *beacon_filter;
|
||||
int ret;
|
||||
|
@ -507,7 +507,7 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
beacon_filter->enable = 0;
|
||||
beacon_filter->enable = enable_filter;
|
||||
beacon_filter->max_num_beacons = 0;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
|
||||
|
@ -525,6 +525,7 @@ out:
|
|||
int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
|
||||
{
|
||||
struct acx_beacon_filter_ie_table *ie_table;
|
||||
int idx = 0;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx beacon filter table");
|
||||
|
@ -535,8 +536,10 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ie_table->num_ie = 0;
|
||||
memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
|
||||
/* configure default beacon pass-through rules */
|
||||
ie_table->num_ie = 1;
|
||||
ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN;
|
||||
ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
|
||||
ie_table, sizeof(*ie_table));
|
||||
|
@ -550,6 +553,35 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_conn_monit_params(struct wl1251 *wl)
|
||||
{
|
||||
struct acx_conn_monit_params *acx;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx connection monitor parameters");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD;
|
||||
acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
|
||||
acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("failed to set connection monitor "
|
||||
"parameters: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_sg_enable(struct wl1251 *wl)
|
||||
{
|
||||
struct acx_bt_wlan_coex *pta;
|
||||
|
@ -916,3 +948,31 @@ out:
|
|||
kfree(mem_conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim)
|
||||
{
|
||||
struct wl1251_acx_wr_tbtt_and_dtim *acx;
|
||||
int ret;
|
||||
|
||||
wl1251_debug(DEBUG_ACX, "acx tbtt and dtim");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->tbtt = tbtt;
|
||||
acx->dtim = dtim;
|
||||
|
||||
ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM,
|
||||
acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1251_warning("failed to set tbtt and dtim: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -450,6 +450,11 @@ struct acx_beacon_filter_option {
|
|||
(BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \
|
||||
BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE))
|
||||
|
||||
#define BEACON_RULE_PASS_ON_CHANGE BIT(0)
|
||||
#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1)
|
||||
|
||||
#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37)
|
||||
|
||||
struct acx_beacon_filter_ie_table {
|
||||
struct acx_header header;
|
||||
|
||||
|
@ -458,6 +463,16 @@ struct acx_beacon_filter_ie_table {
|
|||
u8 pad[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */
|
||||
#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */
|
||||
|
||||
struct acx_conn_monit_params {
|
||||
struct acx_header header;
|
||||
|
||||
u32 synch_fail_thold; /* number of beacons missed */
|
||||
u32 bss_lose_timeout; /* number of TU's from synch fail */
|
||||
};
|
||||
|
||||
enum {
|
||||
SG_ENABLE = 0,
|
||||
SG_DISABLE,
|
||||
|
@ -1134,6 +1149,23 @@ struct wl1251_acx_mem_map {
|
|||
u32 num_rx_mem_blocks;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct wl1251_acx_wr_tbtt_and_dtim {
|
||||
|
||||
struct acx_header header;
|
||||
|
||||
/* Time in TUs between two consecutive beacons */
|
||||
u16 tbtt;
|
||||
|
||||
/*
|
||||
* DTIM period
|
||||
* For BSS: Number of TBTTs in a DTIM period (range: 1-10)
|
||||
* For IBSS: value shall be set to 1
|
||||
*/
|
||||
u8 dtim;
|
||||
u8 padding;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
Host Interrupt Register (WiLink -> Host)
|
||||
|
@ -1273,8 +1305,9 @@ int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
|
|||
int wl1251_acx_group_address_tbl(struct wl1251 *wl);
|
||||
int wl1251_acx_service_period_timeout(struct wl1251 *wl);
|
||||
int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
|
||||
int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
|
||||
int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter);
|
||||
int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
|
||||
int wl1251_acx_conn_monit_params(struct wl1251 *wl);
|
||||
int wl1251_acx_sg_enable(struct wl1251 *wl);
|
||||
int wl1251_acx_sg_cfg(struct wl1251 *wl);
|
||||
int wl1251_acx_cca_threshold(struct wl1251 *wl);
|
||||
|
@ -1288,5 +1321,6 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
|
|||
int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
|
||||
int wl1251_acx_rate_policies(struct wl1251 *wl);
|
||||
int wl1251_acx_mem_cfg(struct wl1251 *wl);
|
||||
int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
|
||||
|
||||
#endif /* __WL1251_ACX_H__ */
|
||||
|
|
|
@ -296,8 +296,12 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
WL1251_ACX_INTR_INIT_COMPLETE;
|
||||
wl1251_boot_target_enable_interrupts(wl);
|
||||
|
||||
/* unmask all mbox events */
|
||||
wl->event_mask = 0xffffffff;
|
||||
wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID |
|
||||
SYNCHRONIZATION_TIMEOUT_EVENT_ID |
|
||||
ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
|
||||
ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
|
||||
REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
|
||||
BT_PTA_PREDICTION_EVENT_ID;
|
||||
|
||||
ret = wl1251_event_unmask(wl);
|
||||
if (ret < 0) {
|
||||
|
@ -314,8 +318,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
|||
static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
||||
{
|
||||
int addr, chunk_num, partition_limit;
|
||||
size_t fw_data_len;
|
||||
u8 *p;
|
||||
size_t fw_data_len, len;
|
||||
u8 *p, *buf;
|
||||
|
||||
/* whal_FwCtrl_LoadFwImageSm() */
|
||||
|
||||
|
@ -334,6 +338,12 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
buf = kmalloc(CHUNK_SIZE, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
wl1251_error("allocation for firmware upload chunk failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START,
|
||||
WL1251_PART_DOWN_MEM_SIZE,
|
||||
WL1251_PART_DOWN_REG_START,
|
||||
|
@ -364,7 +374,11 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
|||
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
|
||||
wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
||||
p, addr);
|
||||
wl1251_mem_write(wl, addr, p, CHUNK_SIZE);
|
||||
|
||||
/* need to copy the chunk for dma */
|
||||
len = CHUNK_SIZE;
|
||||
memcpy(buf, p, len);
|
||||
wl1251_mem_write(wl, addr, buf, len);
|
||||
|
||||
chunk_num++;
|
||||
}
|
||||
|
@ -372,9 +386,16 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
|||
/* 10.4 upload the last chunk */
|
||||
addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
|
||||
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
|
||||
|
||||
/* need to copy the chunk for dma */
|
||||
len = fw_data_len % CHUNK_SIZE;
|
||||
memcpy(buf, p, len);
|
||||
|
||||
wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
|
||||
fw_data_len % CHUNK_SIZE, p, addr);
|
||||
wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
|
||||
len, p, addr);
|
||||
wl1251_mem_write(wl, addr, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -473,13 +494,19 @@ int wl1251_boot(struct wl1251 *wl)
|
|||
goto out;
|
||||
|
||||
/* 2. start processing NVS file */
|
||||
ret = wl1251_boot_upload_nvs(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (wl->use_eeprom) {
|
||||
wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR);
|
||||
msleep(4000);
|
||||
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM);
|
||||
} else {
|
||||
ret = wl1251_boot_upload_nvs(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* write firmware's last address (ie. it's length) to
|
||||
* ACX_EEPROMLESS_IND_REG */
|
||||
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
|
||||
/* write firmware's last address (ie. it's length) to
|
||||
* ACX_EEPROMLESS_IND_REG */
|
||||
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
|
||||
}
|
||||
|
||||
/* 6. read the EEPROM parameters */
|
||||
tmp = wl1251_reg_read32(wl, SCR_PAD2);
|
||||
|
|
|
@ -79,6 +79,21 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
|
|||
}
|
||||
}
|
||||
|
||||
if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) {
|
||||
wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
|
||||
|
||||
/* indicate to the stack, that beacons have been lost */
|
||||
ieee80211_beacon_loss(wl->vif);
|
||||
}
|
||||
|
||||
if (vector & REGAINED_BSS_EVENT_ID) {
|
||||
if (wl->psm_requested) {
|
||||
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,8 @@ int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1251_acx_beacon_filter_opt(wl);
|
||||
/* disable beacon filtering at this stage */
|
||||
ret = wl1251_acx_beacon_filter_opt(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -364,6 +365,11 @@ int wl1251_hw_init(struct wl1251 *wl)
|
|||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1251_acx_conn_monit_params(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_data_path;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1251_hw_init_beacon_filter(wl);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "wl1251.h"
|
||||
#include "wl12xx_80211.h"
|
||||
|
@ -83,7 +84,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl)
|
|||
}
|
||||
|
||||
wl->fw_len = fw->size;
|
||||
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
|
||||
wl->fw = vmalloc(wl->fw_len);
|
||||
|
||||
if (!wl->fw) {
|
||||
wl1251_error("could not allocate memory for the firmware");
|
||||
|
@ -211,9 +212,10 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define WL1251_IRQ_LOOP_COUNT 10
|
||||
static void wl1251_irq_work(struct work_struct *work)
|
||||
{
|
||||
u32 intr;
|
||||
u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
|
||||
struct wl1251 *wl =
|
||||
container_of(work, struct wl1251, irq_work);
|
||||
int ret;
|
||||
|
@ -234,78 +236,86 @@ static void wl1251_irq_work(struct work_struct *work)
|
|||
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
|
||||
wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
|
||||
|
||||
if (wl->data_path) {
|
||||
wl->rx_counter =
|
||||
wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
|
||||
do {
|
||||
if (wl->data_path) {
|
||||
wl->rx_counter = wl1251_mem_read32(
|
||||
wl, wl->data_path->rx_control_addr);
|
||||
|
||||
/* We handle a frmware bug here */
|
||||
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
|
||||
case 0:
|
||||
wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
|
||||
intr &= ~WL1251_ACX_INTR_RX0_DATA;
|
||||
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
case 1:
|
||||
wl1251_debug(DEBUG_IRQ, "RX: FW +1");
|
||||
intr |= WL1251_ACX_INTR_RX0_DATA;
|
||||
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
case 2:
|
||||
wl1251_debug(DEBUG_IRQ, "RX: FW +2");
|
||||
intr |= WL1251_ACX_INTR_RX0_DATA;
|
||||
intr |= WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
default:
|
||||
wl1251_warning("RX: FW and host out of sync: %d",
|
||||
wl->rx_counter - wl->rx_handled);
|
||||
break;
|
||||
/* We handle a frmware bug here */
|
||||
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
|
||||
case 0:
|
||||
wl1251_debug(DEBUG_IRQ,
|
||||
"RX: FW and host in sync");
|
||||
intr &= ~WL1251_ACX_INTR_RX0_DATA;
|
||||
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
case 1:
|
||||
wl1251_debug(DEBUG_IRQ, "RX: FW +1");
|
||||
intr |= WL1251_ACX_INTR_RX0_DATA;
|
||||
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
case 2:
|
||||
wl1251_debug(DEBUG_IRQ, "RX: FW +2");
|
||||
intr |= WL1251_ACX_INTR_RX0_DATA;
|
||||
intr |= WL1251_ACX_INTR_RX1_DATA;
|
||||
break;
|
||||
default:
|
||||
wl1251_warning(
|
||||
"RX: FW and host out of sync: %d",
|
||||
wl->rx_counter - wl->rx_handled);
|
||||
break;
|
||||
}
|
||||
|
||||
wl->rx_handled = wl->rx_counter;
|
||||
|
||||
wl1251_debug(DEBUG_IRQ, "RX counter: %d",
|
||||
wl->rx_counter);
|
||||
}
|
||||
|
||||
wl->rx_handled = wl->rx_counter;
|
||||
intr &= wl->intr_mask;
|
||||
|
||||
if (intr == 0) {
|
||||
wl1251_debug(DEBUG_IRQ, "INTR is 0");
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
|
||||
}
|
||||
if (intr & WL1251_ACX_INTR_RX0_DATA) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
|
||||
wl1251_rx(wl);
|
||||
}
|
||||
|
||||
intr &= wl->intr_mask;
|
||||
if (intr & WL1251_ACX_INTR_RX1_DATA) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
|
||||
wl1251_rx(wl);
|
||||
}
|
||||
|
||||
if (intr == 0) {
|
||||
wl1251_debug(DEBUG_IRQ, "INTR is 0");
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
|
||||
~(wl->intr_mask));
|
||||
if (intr & WL1251_ACX_INTR_TX_RESULT) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
|
||||
wl1251_tx_complete(wl);
|
||||
}
|
||||
|
||||
goto out_sleep;
|
||||
}
|
||||
if (intr & (WL1251_ACX_INTR_EVENT_A |
|
||||
WL1251_ACX_INTR_EVENT_B)) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
|
||||
intr);
|
||||
if (intr & WL1251_ACX_INTR_EVENT_A)
|
||||
wl1251_event_handle(wl, 0);
|
||||
else
|
||||
wl1251_event_handle(wl, 1);
|
||||
}
|
||||
|
||||
if (intr & WL1251_ACX_INTR_RX0_DATA) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
|
||||
wl1251_rx(wl);
|
||||
}
|
||||
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
|
||||
wl1251_debug(DEBUG_IRQ,
|
||||
"WL1251_ACX_INTR_INIT_COMPLETE");
|
||||
|
||||
if (intr & WL1251_ACX_INTR_RX1_DATA) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
|
||||
wl1251_rx(wl);
|
||||
}
|
||||
if (--ctr == 0)
|
||||
break;
|
||||
|
||||
if (intr & WL1251_ACX_INTR_TX_RESULT) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
|
||||
wl1251_tx_complete(wl);
|
||||
}
|
||||
|
||||
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
|
||||
if (intr & WL1251_ACX_INTR_EVENT_A)
|
||||
wl1251_event_handle(wl, 0);
|
||||
else
|
||||
wl1251_event_handle(wl, 1);
|
||||
}
|
||||
|
||||
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
|
||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
|
||||
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
|
||||
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
|
||||
} while (intr);
|
||||
|
||||
out_sleep:
|
||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
|
||||
wl1251_ps_elp_sleep(wl);
|
||||
|
||||
out:
|
||||
|
@ -509,6 +519,12 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
|
|||
conf->type, conf->mac_addr);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
if (wl->vif) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->vif = conf->vif;
|
||||
|
||||
switch (conf->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
|
@ -538,7 +554,12 @@ out:
|
|||
static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_if_init_conf *conf)
|
||||
{
|
||||
struct wl1251 *wl = hw->priv;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
|
||||
wl->vif = NULL;
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static int wl1251_build_null_data(struct wl1251 *wl)
|
||||
|
@ -555,7 +576,8 @@ static int wl1251_build_null_data(struct wl1251 *wl)
|
|||
|
||||
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
|
||||
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC);
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_TODS);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
|
||||
sizeof(template));
|
||||
|
@ -568,7 +590,10 @@ static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
|
|||
|
||||
memcpy(template.bssid, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.ta, wl->mac_addr, ETH_ALEN);
|
||||
template.aid = aid;
|
||||
|
||||
/* aid in PS-Poll has its two MSBs each set to 1 */
|
||||
template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
|
||||
|
||||
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
|
||||
|
||||
return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
|
||||
|
@ -1090,8 +1115,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
wl->beacon_int = bss_conf->beacon_int;
|
||||
wl->dtim_period = bss_conf->dtim_period;
|
||||
|
||||
/* FIXME: call join */
|
||||
|
||||
ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
|
||||
wl->dtim_period);
|
||||
wl->aid = bss_conf->aid;
|
||||
|
||||
ret = wl1251_build_ps_poll(wl, wl->aid);
|
||||
|
@ -1312,7 +1337,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
|
|||
|
||||
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM |
|
||||
IEEE80211_HW_SUPPORTS_PS;
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_BEACON_FILTER;
|
||||
|
||||
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
wl->hw->wiphy->max_scan_ssids = 1;
|
||||
|
@ -1355,6 +1381,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
|
|||
skb_queue_head_init(&wl->tx_queue);
|
||||
|
||||
INIT_WORK(&wl->filter_work, wl1251_filter_work);
|
||||
INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
|
||||
wl->channel = WL1251_DEFAULT_CHANNEL;
|
||||
wl->scanning = false;
|
||||
wl->default_key = 0;
|
||||
|
@ -1372,6 +1399,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
|
|||
wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
|
||||
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
||||
wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
|
||||
wl->vif = NULL;
|
||||
|
||||
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
|
||||
wl->tx_frames[i] = NULL;
|
||||
|
@ -1413,7 +1441,7 @@ int wl1251_free_hw(struct wl1251 *wl)
|
|||
|
||||
kfree(wl->target_mem_map);
|
||||
kfree(wl->data_path);
|
||||
kfree(wl->fw);
|
||||
vfree(wl->fw);
|
||||
wl->fw = NULL;
|
||||
kfree(wl->nvs);
|
||||
wl->nvs = NULL;
|
||||
|
|
|
@ -28,17 +28,41 @@
|
|||
|
||||
#define WL1251_WAKEUP_TIMEOUT 2000
|
||||
|
||||
void wl1251_elp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
struct wl1251 *wl;
|
||||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
wl = container_of(dwork, struct wl1251, elp_work);
|
||||
|
||||
wl1251_debug(DEBUG_PSM, "elp work");
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->elp || !wl->psm)
|
||||
goto out;
|
||||
|
||||
wl1251_debug(DEBUG_PSM, "chip to elp");
|
||||
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
||||
wl->elp = true;
|
||||
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
#define ELP_ENTRY_DELAY 5
|
||||
|
||||
/* Routines to toggle sleep mode while in ELP */
|
||||
void wl1251_ps_elp_sleep(struct wl1251 *wl)
|
||||
{
|
||||
if (wl->elp || !wl->psm)
|
||||
return;
|
||||
unsigned long delay;
|
||||
|
||||
wl1251_debug(DEBUG_PSM, "chip to elp");
|
||||
|
||||
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
||||
|
||||
wl->elp = true;
|
||||
if (wl->psm) {
|
||||
cancel_delayed_work(&wl->elp_work);
|
||||
delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
|
||||
}
|
||||
}
|
||||
|
||||
int wl1251_ps_elp_wakeup(struct wl1251 *wl)
|
||||
|
@ -119,6 +143,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
|
|||
case STATION_POWER_SAVE_MODE:
|
||||
wl1251_debug(DEBUG_PSM, "entering psm");
|
||||
|
||||
/* enable beacon filtering */
|
||||
ret = wl1251_acx_beacon_filter_opt(wl, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1251_acx_wake_up_conditions(wl,
|
||||
WAKE_UP_EVENT_DTIM_BITMAP,
|
||||
wl->listen_int);
|
||||
|
@ -142,6 +171,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* disable beacon filtering */
|
||||
ret = wl1251_acx_beacon_filter_opt(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1251_acx_wake_up_conditions(wl,
|
||||
WAKE_UP_EVENT_DTIM_BITMAP,
|
||||
wl->listen_int);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
|
||||
void wl1251_ps_elp_sleep(struct wl1251 *wl);
|
||||
int wl1251_ps_elp_wakeup(struct wl1251 *wl);
|
||||
void wl1251_elp_work(struct work_struct *work);
|
||||
|
||||
|
||||
#endif /* __WL1251_PS_H__ */
|
||||
|
|
|
@ -370,6 +370,7 @@ enum wl12xx_acx_int_reg {
|
|||
EEPROM location specified in the EE_ADDR register.
|
||||
The Wlan hardware hardware clears this bit automatically.
|
||||
*===============================================*/
|
||||
#define EE_CTL (REGISTERS_BASE + 0x2000)
|
||||
#define ACX_EE_CTL_REG EE_CTL
|
||||
#define EE_WRITE 0x00000001ul
|
||||
#define EE_READ 0x00000002ul
|
||||
|
@ -380,6 +381,7 @@ enum wl12xx_acx_int_reg {
|
|||
This register specifies the address
|
||||
within the EEPROM from/to which to read/write data.
|
||||
===============================================*/
|
||||
#define EE_ADDR (REGISTERS_BASE + 0x2008)
|
||||
#define ACX_EE_ADDR_REG EE_ADDR
|
||||
|
||||
/*===============================================
|
||||
|
@ -389,8 +391,12 @@ enum wl12xx_acx_int_reg {
|
|||
data from the EEPROM or the write data
|
||||
to be written to the EEPROM.
|
||||
===============================================*/
|
||||
#define EE_DATA (REGISTERS_BASE + 0x2004)
|
||||
#define ACX_EE_DATA_REG EE_DATA
|
||||
|
||||
#define EEPROM_ACCESS_TO 10000 /* timeout counter */
|
||||
#define START_EEPROM_MGR 0x00000001
|
||||
|
||||
/*===============================================
|
||||
EEPROM Base Address - 32bit RW
|
||||
------------------------------------------
|
||||
|
|
|
@ -72,10 +72,6 @@ static void wl1251_rx_status(struct wl1251 *wl,
|
|||
}
|
||||
|
||||
status->signal = desc->rssi;
|
||||
status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
|
||||
(WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
|
||||
status->qual = min(status->qual, 100);
|
||||
status->qual = max(status->qual, 0);
|
||||
|
||||
/*
|
||||
* FIXME: guessing that snr needs to be divided by two, otherwise
|
||||
|
|
|
@ -270,6 +270,8 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
wl->use_eeprom = pdata->use_eeprom;
|
||||
|
||||
ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
|
||||
if (ret < 0) {
|
||||
wl1251_error("request_irq() failed: %d", ret);
|
||||
|
|
|
@ -381,7 +381,7 @@ static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr)
|
|||
|
||||
static int wl3501_esbq_req_test(struct wl3501_card *this)
|
||||
{
|
||||
u8 tmp;
|
||||
u8 tmp = 0;
|
||||
|
||||
wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp));
|
||||
return tmp & 0x80;
|
||||
|
|
|
@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev)
|
|||
put_device(dev->dev);
|
||||
}
|
||||
|
||||
static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
|
||||
{
|
||||
if (drv)
|
||||
get_driver(&drv->drv);
|
||||
return drv;
|
||||
}
|
||||
|
||||
static inline void ssb_driver_put(struct ssb_driver *drv)
|
||||
{
|
||||
if (drv)
|
||||
put_driver(&drv->drv);
|
||||
}
|
||||
|
||||
static int ssb_device_resume(struct device *dev)
|
||||
{
|
||||
struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
|
||||
|
@ -210,90 +223,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
|
|||
EXPORT_SYMBOL(ssb_bus_suspend);
|
||||
|
||||
#ifdef CONFIG_SSB_SPROM
|
||||
int ssb_devices_freeze(struct ssb_bus *bus)
|
||||
/** ssb_devices_freeze - Freeze all devices on the bus.
|
||||
*
|
||||
* After freezing no device driver will be handling a device
|
||||
* on this bus anymore. ssb_devices_thaw() must be called after
|
||||
* a successful freeze to reactivate the devices.
|
||||
*
|
||||
* @bus: The bus.
|
||||
* @ctx: Context structure. Pass this to ssb_devices_thaw().
|
||||
*/
|
||||
int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)
|
||||
{
|
||||
struct ssb_device *dev;
|
||||
struct ssb_driver *drv;
|
||||
int err = 0;
|
||||
int i;
|
||||
pm_message_t state = PMSG_FREEZE;
|
||||
struct ssb_device *sdev;
|
||||
struct ssb_driver *sdrv;
|
||||
unsigned int i;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->bus = bus;
|
||||
SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen));
|
||||
|
||||
/* First check that we are capable to freeze all devices. */
|
||||
for (i = 0; i < bus->nr_devices; i++) {
|
||||
dev = &(bus->devices[i]);
|
||||
if (!dev->dev ||
|
||||
!dev->dev->driver ||
|
||||
!device_is_registered(dev->dev))
|
||||
sdev = ssb_device_get(&bus->devices[i]);
|
||||
|
||||
if (!sdev->dev || !sdev->dev->driver ||
|
||||
!device_is_registered(sdev->dev)) {
|
||||
ssb_device_put(sdev);
|
||||
continue;
|
||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
||||
if (!drv)
|
||||
continue;
|
||||
if (!drv->suspend) {
|
||||
/* Nope, can't suspend this one. */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
/* Now suspend all devices */
|
||||
for (i = 0; i < bus->nr_devices; i++) {
|
||||
dev = &(bus->devices[i]);
|
||||
if (!dev->dev ||
|
||||
!dev->dev->driver ||
|
||||
!device_is_registered(dev->dev))
|
||||
sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
|
||||
if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
|
||||
ssb_device_put(sdev);
|
||||
continue;
|
||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
||||
if (!drv)
|
||||
continue;
|
||||
err = drv->suspend(dev, state);
|
||||
if (err) {
|
||||
ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
|
||||
dev_name(dev->dev));
|
||||
goto err_unwind;
|
||||
}
|
||||
sdrv->remove(sdev);
|
||||
ctx->device_frozen[i] = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_unwind:
|
||||
for (i--; i >= 0; i--) {
|
||||
dev = &(bus->devices[i]);
|
||||
if (!dev->dev ||
|
||||
!dev->dev->driver ||
|
||||
!device_is_registered(dev->dev))
|
||||
continue;
|
||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
||||
if (!drv)
|
||||
continue;
|
||||
if (drv->resume)
|
||||
drv->resume(dev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ssb_devices_thaw(struct ssb_bus *bus)
|
||||
/** ssb_devices_thaw - Unfreeze all devices on the bus.
|
||||
*
|
||||
* This will re-attach the device drivers and re-init the devices.
|
||||
*
|
||||
* @ctx: The context structure from ssb_devices_freeze()
|
||||
*/
|
||||
int ssb_devices_thaw(struct ssb_freeze_context *ctx)
|
||||
{
|
||||
struct ssb_device *dev;
|
||||
struct ssb_driver *drv;
|
||||
int err;
|
||||
int i;
|
||||
struct ssb_bus *bus = ctx->bus;
|
||||
struct ssb_device *sdev;
|
||||
struct ssb_driver *sdrv;
|
||||
unsigned int i;
|
||||
int err, result = 0;
|
||||
|
||||
for (i = 0; i < bus->nr_devices; i++) {
|
||||
dev = &(bus->devices[i]);
|
||||
if (!dev->dev ||
|
||||
!dev->dev->driver ||
|
||||
!device_is_registered(dev->dev))
|
||||
if (!ctx->device_frozen[i])
|
||||
continue;
|
||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
||||
if (!drv)
|
||||
sdev = &bus->devices[i];
|
||||
|
||||
if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver))
|
||||
continue;
|
||||
if (SSB_WARN_ON(!drv->resume))
|
||||
sdrv = drv_to_ssb_drv(sdev->dev->driver);
|
||||
if (SSB_WARN_ON(!sdrv || !sdrv->probe))
|
||||
continue;
|
||||
err = drv->resume(dev);
|
||||
|
||||
err = sdrv->probe(sdev, &sdev->id);
|
||||
if (err) {
|
||||
ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
|
||||
dev_name(dev->dev));
|
||||
dev_name(sdev->dev));
|
||||
result = err;
|
||||
}
|
||||
ssb_driver_put(sdrv);
|
||||
ssb_device_put(sdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
#endif /* CONFIG_SSB_SPROM */
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
|
|||
dev->bus = bus;
|
||||
dev->ops = bus->ops;
|
||||
|
||||
ssb_dprintk(KERN_INFO PFX
|
||||
printk(KERN_DEBUG PFX
|
||||
"Core %d found: %s "
|
||||
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
|
||||
i, ssb_core_name(dev->id.coreid),
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include "ssb_private.h"
|
||||
|
||||
#include <linux/ctype.h>
|
||||
|
||||
|
||||
static const struct ssb_sprom *fallback_sprom;
|
||||
|
||||
|
@ -33,17 +35,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
|
|||
static int hex2sprom(u16 *sprom, const char *dump, size_t len,
|
||||
size_t sprom_size_words)
|
||||
{
|
||||
char tmp[5] = { 0 };
|
||||
int cnt = 0;
|
||||
char c, tmp[5] = { 0 };
|
||||
int err, cnt = 0;
|
||||
unsigned long parsed;
|
||||
|
||||
if (len < sprom_size_words * 2)
|
||||
/* Strip whitespace at the end. */
|
||||
while (len) {
|
||||
c = dump[len - 1];
|
||||
if (!isspace(c) && c != '\0')
|
||||
break;
|
||||
len--;
|
||||
}
|
||||
/* Length must match exactly. */
|
||||
if (len != sprom_size_words * 4)
|
||||
return -EINVAL;
|
||||
|
||||
while (cnt < sprom_size_words) {
|
||||
memcpy(tmp, dump, 4);
|
||||
dump += 4;
|
||||
parsed = simple_strtoul(tmp, NULL, 16);
|
||||
err = strict_strtoul(tmp, 16, &parsed);
|
||||
if (err)
|
||||
return err;
|
||||
sprom[cnt++] = swab16((u16)parsed);
|
||||
}
|
||||
|
||||
|
@ -90,6 +102,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
|
|||
u16 *sprom;
|
||||
int res = 0, err = -ENOMEM;
|
||||
size_t sprom_size_words = bus->sprom_size;
|
||||
struct ssb_freeze_context freeze;
|
||||
|
||||
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
|
||||
if (!sprom)
|
||||
|
@ -111,18 +124,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
|
|||
err = -ERESTARTSYS;
|
||||
if (mutex_lock_interruptible(&bus->sprom_mutex))
|
||||
goto out_kfree;
|
||||
err = ssb_devices_freeze(bus);
|
||||
if (err == -EOPNOTSUPP) {
|
||||
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
|
||||
"No suspend support. Is CONFIG_PM enabled?\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
err = ssb_devices_freeze(bus, &freeze);
|
||||
if (err) {
|
||||
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
res = sprom_write(bus, sprom);
|
||||
err = ssb_devices_thaw(bus);
|
||||
err = ssb_devices_thaw(&freeze);
|
||||
if (err)
|
||||
ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
|
||||
out_unlock:
|
||||
|
|
|
@ -176,13 +176,21 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
|
|||
|
||||
/* core.c */
|
||||
extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
|
||||
extern int ssb_devices_freeze(struct ssb_bus *bus);
|
||||
extern int ssb_devices_thaw(struct ssb_bus *bus);
|
||||
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
|
||||
int ssb_for_each_bus_call(unsigned long data,
|
||||
int (*func)(struct ssb_bus *bus, unsigned long data));
|
||||
extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev);
|
||||
|
||||
struct ssb_freeze_context {
|
||||
/* Pointer to the bus */
|
||||
struct ssb_bus *bus;
|
||||
/* Boolean list to indicate whether a device is frozen on this bus. */
|
||||
bool device_frozen[SSB_MAX_NR_CORES];
|
||||
};
|
||||
extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx);
|
||||
extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
|
||||
|
||||
|
||||
|
||||
/* b43_pci_bridge.c */
|
||||
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
#define IEEE80211_MAX_SSID_LEN 32
|
||||
|
||||
#define IEEE80211_MAX_MESH_ID_LEN 32
|
||||
#define IEEE80211_MESH_CONFIG_LEN 7
|
||||
|
||||
#define IEEE80211_QOS_CTL_LEN 2
|
||||
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
|
||||
|
@ -554,6 +553,21 @@ struct ieee80211_tim_ie {
|
|||
u8 virtual_map[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ieee80211_meshconf_ie
|
||||
*
|
||||
* This structure refers to "Mesh Configuration information element"
|
||||
*/
|
||||
struct ieee80211_meshconf_ie {
|
||||
u8 meshconf_psel;
|
||||
u8 meshconf_pmetric;
|
||||
u8 meshconf_congest;
|
||||
u8 meshconf_synch;
|
||||
u8 meshconf_auth;
|
||||
u8 meshconf_form;
|
||||
u8 meshconf_cap;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ieee80211_rann_ie
|
||||
*
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
|
||||
* release skb->dst
|
||||
*/
|
||||
#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
|
||||
|
||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||
#define IF_GET_PROTO 0x0002
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
* @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
|
||||
* @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
|
||||
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
|
||||
* @RFKILL_TYPE_GPS: switch is on a GPS device.
|
||||
* @RFKILL_TYPE_FM: switch is on a FM radio device.
|
||||
* @NUM_RFKILL_TYPES: number of defined rfkill types
|
||||
*/
|
||||
enum rfkill_type {
|
||||
|
@ -45,6 +47,7 @@ enum rfkill_type {
|
|||
RFKILL_TYPE_WIMAX,
|
||||
RFKILL_TYPE_WWAN,
|
||||
RFKILL_TYPE_GPS,
|
||||
RFKILL_TYPE_FM,
|
||||
NUM_RFKILL_TYPES,
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
struct wl12xx_platform_data {
|
||||
void (*set_power)(bool enable);
|
||||
bool use_eeprom;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1108,27 +1108,50 @@ struct cfg80211_ops {
|
|||
*/
|
||||
|
||||
/**
|
||||
* struct wiphy - wireless hardware description
|
||||
* @idx: the wiphy index assigned to this item
|
||||
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
|
||||
* @custom_regulatory: tells us the driver for this device
|
||||
* enum wiphy_flags - wiphy capability flags
|
||||
*
|
||||
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
|
||||
* has its own custom regulatory domain and cannot identify the
|
||||
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
|
||||
* we will disregard the first regulatory hint (when the
|
||||
* initiator is %REGDOM_SET_BY_CORE).
|
||||
* @strict_regulatory: tells us the driver for this device will ignore
|
||||
* regulatory domain settings until it gets its own regulatory domain
|
||||
* via its regulatory_hint(). After its gets its own regulatory domain
|
||||
* it will only allow further regulatory domain settings to further
|
||||
* enhance compliance. For example if channel 13 and 14 are disabled
|
||||
* by this regulatory domain no user regulatory domain can enable these
|
||||
* channels at a later time. This can be used for devices which do not
|
||||
* have calibration information gauranteed for frequencies or settings
|
||||
* outside of its regulatory domain.
|
||||
* @disable_beacon_hints: enable this if your driver needs to ensure that
|
||||
* passive scan flags and beaconing flags may not be lifted by cfg80211
|
||||
* due to regulatory beacon hints. For more information on beacon
|
||||
* @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
|
||||
* ignore regulatory domain settings until it gets its own regulatory
|
||||
* domain via its regulatory_hint(). After its gets its own regulatory
|
||||
* domain it will only allow further regulatory domain settings to
|
||||
* further enhance compliance. For example if channel 13 and 14 are
|
||||
* disabled by this regulatory domain no user regulatory domain can
|
||||
* enable these channels at a later time. This can be used for devices
|
||||
* which do not have calibration information gauranteed for frequencies
|
||||
* or settings outside of its regulatory domain.
|
||||
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
|
||||
* that passive scan flags and beaconing flags may not be lifted by
|
||||
* cfg80211 due to regulatory beacon hints. For more information on beacon
|
||||
* hints read the documenation for regulatory_hint_found_beacon()
|
||||
* @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
|
||||
* wiphy at all
|
||||
* @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
|
||||
* by default -- this flag will be set depending on the kernel's default
|
||||
* on wiphy_new(), but can be changed by the driver if it has a good
|
||||
* reason to override the default
|
||||
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
|
||||
* on a VLAN interface)
|
||||
* @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
|
||||
*/
|
||||
enum wiphy_flags {
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
|
||||
WIPHY_FLAG_STRICT_REGULATORY = BIT(1),
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
|
||||
WIPHY_FLAG_NETNS_OK = BIT(3),
|
||||
WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
|
||||
WIPHY_FLAG_4ADDR_AP = BIT(5),
|
||||
WIPHY_FLAG_4ADDR_STATION = BIT(6),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wiphy - wireless hardware description
|
||||
* @idx: the wiphy index assigned to this item
|
||||
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
|
||||
* @reg_notifier: the driver's regulatory notification callback
|
||||
* @regd: the driver's regulatory domain, if one was requested via
|
||||
* the regulatory_hint() API. This can be used by the driver
|
||||
|
@ -1143,11 +1166,6 @@ struct cfg80211_ops {
|
|||
* -1 = fragmentation disabled, only odd values >= 256 used
|
||||
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
|
||||
* @net: the network namespace this wiphy currently lives in
|
||||
* @netnsok: if set to false, do not allow changing the netns of this
|
||||
* wiphy at all
|
||||
* @ps_default: default for powersave, will be set depending on the
|
||||
* kernel's default on wiphy_new(), but can be changed by the
|
||||
* driver if it has a good reason to override the default
|
||||
*/
|
||||
struct wiphy {
|
||||
/* assign these fields before you register the wiphy */
|
||||
|
@ -1158,12 +1176,7 @@ struct wiphy {
|
|||
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
|
||||
u16 interface_modes;
|
||||
|
||||
bool custom_regulatory;
|
||||
bool strict_regulatory;
|
||||
bool disable_beacon_hints;
|
||||
|
||||
bool netnsok;
|
||||
bool ps_default;
|
||||
u32 flags;
|
||||
|
||||
enum cfg80211_signal_type signal_type;
|
||||
|
||||
|
@ -1358,6 +1371,10 @@ struct cfg80211_cached_keys;
|
|||
* @ssid_len: (private) Used by the internal configuration code
|
||||
* @wext: (private) Used by the internal wireless extensions compat code
|
||||
* @wext_bssid: (private) Used by the internal wireless extensions compat code
|
||||
* @use_4addr: indicates 4addr mode is used on this interface, must be
|
||||
* set by driver (if supported) on add_interface BEFORE registering the
|
||||
* netdev and may otherwise be used by driver read-only, will be update
|
||||
* by cfg80211 on change_interface
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
|
@ -1371,6 +1388,8 @@ struct wireless_dev {
|
|||
|
||||
struct work_struct cleanup_work;
|
||||
|
||||
bool use_4addr;
|
||||
|
||||
/* currently used for IBSS and SME - might be rearranged later */
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
|
@ -1819,6 +1838,18 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
|
|||
*/
|
||||
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
|
||||
|
||||
/**
|
||||
* __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled
|
||||
* @dev: network device
|
||||
* @addr: The MAC address of the device with which the authentication timed out
|
||||
*
|
||||
* When a pending authentication had no action yet, the driver may decide
|
||||
* to not send a deauth frame, but in that case must calls this function
|
||||
* to tell cfg80211 about this decision. It is only valid to call this
|
||||
* function within the deauth() callback.
|
||||
*/
|
||||
void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr);
|
||||
|
||||
/**
|
||||
* cfg80211_send_rx_assoc - notification of processed association
|
||||
* @dev: network device
|
||||
|
|
|
@ -219,7 +219,7 @@ struct ieee80211_bss_conf {
|
|||
*
|
||||
* These flags are used with the @flags member of &ieee80211_tx_info.
|
||||
*
|
||||
* @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
|
||||
* @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame.
|
||||
* @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
|
||||
* number to this frame, taking care of not overwriting the fragment
|
||||
* number and increasing the sequence number only when the
|
||||
|
@ -390,10 +390,12 @@ struct ieee80211_tx_rate {
|
|||
* @control: union for control data
|
||||
* @status: union for status data
|
||||
* @driver_data: array of driver_data pointers
|
||||
* @ampdu_ack_len: number of aggregated frames.
|
||||
* @ampdu_ack_len: number of acked aggregated frames.
|
||||
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
||||
* @ampdu_ack_map: block ack bit map for the aggregation.
|
||||
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
||||
* @ampdu_len: number of aggregated frames.
|
||||
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
||||
* @ack_signal: signal strength of the ACK frame
|
||||
*/
|
||||
struct ieee80211_tx_info {
|
||||
|
@ -428,7 +430,8 @@ struct ieee80211_tx_info {
|
|||
u8 ampdu_ack_len;
|
||||
u64 ampdu_ack_map;
|
||||
int ack_signal;
|
||||
/* 8 bytes free */
|
||||
u8 ampdu_len;
|
||||
/* 7 bytes free */
|
||||
} status;
|
||||
struct {
|
||||
struct ieee80211_tx_rate driver_rates[
|
||||
|
@ -852,6 +855,19 @@ enum ieee80211_tkip_key_type {
|
|||
* any particular flags. There are some exceptions to this rule,
|
||||
* however, so you are advised to review these flags carefully.
|
||||
*
|
||||
* @IEEE80211_HW_HAS_RATE_CONTROL:
|
||||
* The hardware or firmware includes rate control, and cannot be
|
||||
* controlled by the stack. As such, no rate control algorithm
|
||||
* should be instantiated, and the TX rate reported to userspace
|
||||
* will be taken from the TX status instead of the rate control
|
||||
* algorithm.
|
||||
* Note that this requires that the driver implement a number of
|
||||
* callbacks so it has the correct information, it needs to have
|
||||
* the @set_rts_threshold callback and must look at the BSS config
|
||||
* @use_cts_prot for G/N protection, @use_short_slot for slot
|
||||
* timing in 2.4 GHz and @use_short_preamble for preambles for
|
||||
* CCK frames.
|
||||
*
|
||||
* @IEEE80211_HW_RX_INCLUDES_FCS:
|
||||
* Indicates that received frames passed to the stack include
|
||||
* the FCS at the end.
|
||||
|
@ -910,6 +926,7 @@ enum ieee80211_tkip_key_type {
|
|||
* avoid waking up cpu.
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||||
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
|
||||
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
|
||||
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
|
||||
|
@ -1505,6 +1522,7 @@ struct ieee80211_ops {
|
|||
void (*reset_tsf)(struct ieee80211_hw *hw);
|
||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
||||
|
||||
|
@ -2026,8 +2044,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
|||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient
|
||||
* @sta: the station for which to start a BA session
|
||||
* @tid: the TID to BA on.
|
||||
*
|
||||
* Return: success if addBA request was sent, failure otherwise
|
||||
|
@ -2036,22 +2053,22 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
|||
* the need to start aggregation on a certain RA/TID, the session level
|
||||
* will be managed by the mac80211.
|
||||
*/
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session.
|
||||
*/
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the TID to BA on.
|
||||
*
|
||||
|
@ -2059,13 +2076,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid);
|
|||
* finished with preparations for the BA session.
|
||||
* This version of the function is IRQ-safe.
|
||||
*/
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
|
||||
u16 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @ra: receiver address of the BA session recipient
|
||||
* @sta: the station whose BA session to stop
|
||||
* @tid: the TID to stop BA.
|
||||
* @initiator: if indicates initiator DELBA frame will be sent.
|
||||
*
|
||||
|
@ -2075,24 +2091,23 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
|||
* the need to stop aggregation on a certain RA/TID, the session level
|
||||
* will be managed by the mac80211.
|
||||
*/
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||
u8 *ra, u16 tid,
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the desired TID to BA on.
|
||||
*
|
||||
* This function must be called by low level driver once it has
|
||||
* finished with preparations for the BA session tear down.
|
||||
*/
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
|
||||
|
||||
/**
|
||||
* ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
||||
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
|
||||
* @ra: receiver address of the BA session recipient.
|
||||
* @tid: the desired TID to BA on.
|
||||
*
|
||||
|
@ -2100,7 +2115,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid);
|
|||
* finished with preparations for the BA session tear down.
|
||||
* This version of the function is IRQ-safe.
|
||||
*/
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
|
||||
u16 tid);
|
||||
|
||||
/**
|
||||
|
|
|
@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|||
if (dev->br_port != NULL)
|
||||
return -EBUSY;
|
||||
|
||||
/* No bridging devices that dislike that (e.g. wireless) */
|
||||
if (dev->priv_flags & IFF_DONT_BRIDGE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
p = new_nbp(br, dev);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
|
|
@ -2,7 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o
|
|||
|
||||
# mac80211 objects
|
||||
mac80211-y := \
|
||||
main.o \
|
||||
main.o status.o \
|
||||
sta_info.o \
|
||||
wep.o \
|
||||
wpa.o \
|
||||
|
|
|
@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
sta->sta.addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP,
|
||||
if (drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL))
|
||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||
"aggregation for tid %d\n", tid);
|
||||
|
@ -170,7 +171,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
|||
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
|
||||
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
|
@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
goto end;
|
||||
}
|
||||
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START,
|
||||
ret = drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
|
|
|
@ -91,7 +91,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
|||
mgmt->u.action.u.addba_req.start_seq_num =
|
||||
cpu_to_le16(start_seq_num << 4);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
|
||||
|
@ -120,7 +120,8 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
|
|||
bar->control = cpu_to_le16(bar_control);
|
||||
bar->start_seq_num = cpu_to_le16(ssn);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
|
@ -138,7 +139,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
||||
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP,
|
||||
ret = drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_TX_STOP,
|
||||
&sta->sta, tid, NULL);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
|
@ -196,11 +198,11 @@ static inline int ieee80211_ac_from_tid(int tid)
|
|||
return ieee802_1d_to_ac[tid & 7];
|
||||
}
|
||||
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u8 *state;
|
||||
int ret = 0;
|
||||
u16 start_seq_num;
|
||||
|
@ -208,52 +210,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
if (WARN_ON(!local->ops->ampdu_action))
|
||||
return -EINVAL;
|
||||
|
||||
if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
|
||||
if ((tid >= STA_TID_NUM) ||
|
||||
!(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
||||
ra, tid);
|
||||
pubsta->addr, tid);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Could not find the station\n");
|
||||
#endif
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* The aggregation code is not prepared to handle
|
||||
* anything but STA/AP due to the BSSID handling.
|
||||
* IBSS could work in the code but isn't supported
|
||||
* by drivers or the standard.
|
||||
*/
|
||||
if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sta->sdata->vif.type != NL80211_IFTYPE_AP) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "Suspend in progress. "
|
||||
"Denying BA session request\n");
|
||||
#endif
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock(&local->ampdu_lock);
|
||||
|
||||
sdata = sta->sdata;
|
||||
|
||||
/* we have tried too many times, receiver does not want A-MPDU */
|
||||
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
|
||||
ret = -EBUSY;
|
||||
|
@ -310,8 +297,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
|
||||
start_seq_num = sta->tid_seq[tid];
|
||||
|
||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num);
|
||||
ret = drv_ampdu_action(local, &sdata->vif,
|
||||
IEEE80211_AMPDU_TX_START,
|
||||
pubsta, tid, &start_seq_num);
|
||||
|
||||
if (ret) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
|
@ -336,7 +324,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
sta->ampdu_mlme.dialog_token_allocator;
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
|
||||
|
||||
ieee80211_send_addba_request(sta->sdata, ra, tid,
|
||||
ieee80211_send_addba_request(sdata, pubsta->addr, tid,
|
||||
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
|
||||
sta->ampdu_mlme.tid_tx[tid]->ssn,
|
||||
0x40, 5000);
|
||||
|
@ -348,7 +336,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
||||
#endif
|
||||
goto unlock;
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
||||
|
@ -360,8 +348,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
err_unlock_sta:
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
|
||||
|
@ -428,13 +414,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
|||
ieee80211_agg_splice_finish(local, sta, tid);
|
||||
spin_unlock(&local->ampdu_lock);
|
||||
|
||||
drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
drv_ampdu_action(local, &sta->sdata->vif,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL);
|
||||
}
|
||||
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
|
||||
|
@ -483,10 +471,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
|
||||
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
|
@ -501,6 +490,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
|||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
ra_tid->vif = vif;
|
||||
|
||||
skb->pkt_type = IEEE80211_ADDBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
|
@ -535,13 +525,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||
u8 *ra, u16 tid,
|
||||
int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct sta_info *sta;
|
||||
int ret = 0;
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (WARN_ON(!local->ops->ampdu_action))
|
||||
return -EINVAL;
|
||||
|
@ -549,22 +538,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
|||
if (tid >= STA_TID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(local, ra);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u8 *state;
|
||||
|
||||
|
@ -627,10 +608,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
|
||||
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
||||
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
|
||||
const u8 *ra, u16 tid)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_ra_tid *ra_tid;
|
||||
struct sk_buff *skb = dev_alloc_skb(0);
|
||||
|
||||
|
@ -645,6 +627,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
|
|||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||
ra_tid->tid = tid;
|
||||
ra_tid->vif = vif;
|
||||
|
||||
skb->pkt_type = IEEE80211_DELBA_MSG;
|
||||
skb_queue_tail(&local->skb_queue, skb);
|
||||
|
|
|
@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type,
|
|||
if (!nl80211_type_check(type))
|
||||
return false;
|
||||
|
||||
if (params->use_4addr > 0) {
|
||||
switch(type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
|||
params->mesh_id_len,
|
||||
params->mesh_id);
|
||||
|
||||
if (params->use_4addr >= 0)
|
||||
sdata->use_4addr = !!params->use_4addr;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
|
||||
return 0;
|
||||
|
||||
if (type == NL80211_IFTYPE_AP_VLAN &&
|
||||
params && params->use_4addr == 0)
|
||||
rcu_assign_pointer(sdata->u.vlan.sta, NULL);
|
||||
else if (type == NL80211_IFTYPE_STATION &&
|
||||
params && params->use_4addr >= 0)
|
||||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
|
||||
sdata->u.mntr_flags = *flags;
|
||||
return 0;
|
||||
}
|
||||
|
@ -398,13 +393,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
|||
static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
int idx, u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta;
|
||||
int ret = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get_by_idx(local, idx, dev);
|
||||
sta = sta_info_get_by_idx(sdata, idx);
|
||||
if (sta) {
|
||||
ret = 0;
|
||||
memcpy(mac, sta->sta.addr, ETH_ALEN);
|
||||
|
@ -827,9 +822,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vlansdata->use_4addr) {
|
||||
if (vlansdata->u.vlan.sta)
|
||||
if (params->vlan->ieee80211_ptr->use_4addr) {
|
||||
if (vlansdata->u.vlan.sta) {
|
||||
rcu_read_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
|
|||
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
|
||||
local->wep_iv & 0xffffff);
|
||||
DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
|
||||
local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
|
||||
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
|
||||
|
||||
static ssize_t tsf_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
|
|
@ -157,6 +157,34 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
|
|||
}
|
||||
STA_OPS(agg_status);
|
||||
|
||||
static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[200], *p = buf;
|
||||
int i;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
|
||||
htc->ht_supported ? "" : "not ");
|
||||
if (htc->ht_supported) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
|
||||
htc->ampdu_factor, htc->ampdu_density);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
|
||||
htc->mcs.rx_mask[i]);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
|
||||
le16_to_cpu(htc->mcs.rx_highest));
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
|
||||
htc->mcs.tx_params);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
}
|
||||
STA_OPS(ht_capa);
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, \
|
||||
sta->debugfs.dir, sta, &sta_ ##name## _ops);
|
||||
|
@ -207,6 +235,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
|||
DEBUGFS_ADD(last_signal);
|
||||
DEBUGFS_ADD(last_noise);
|
||||
DEBUGFS_ADD(wep_weak_iv_count);
|
||||
DEBUGFS_ADD(ht_capa);
|
||||
}
|
||||
|
||||
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
|
||||
|
|
|
@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
|||
}
|
||||
|
||||
static inline int drv_ampdu_action(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, action,
|
||||
ret = local->ops->ampdu_action(&local->hw, vif, action,
|
||||
sta, tid, ssn);
|
||||
trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
|
||||
trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon,
|
|||
|
||||
TRACE_EVENT(drv_ampdu_action,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, int ret),
|
||||
|
||||
TP_ARGS(local, action, sta, tid, ssn, ret),
|
||||
TP_ARGS(local, vif, action, sta, tid, ssn, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
|
@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
__field(u16, tid)
|
||||
__field(u16, ssn)
|
||||
__field(int, ret)
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->ret = ret;
|
||||
__entry->action = action;
|
||||
|
@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action,
|
|||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
|
||||
)
|
||||
);
|
||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
|
|
@ -134,14 +134,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
|||
mgmt->u.action.u.delba.params = cpu_to_le16(params);
|
||||
mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u16 tid, params;
|
||||
u16 initiator;
|
||||
|
||||
|
@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
|||
sta->ampdu_mlme.tid_state_tx[tid] =
|
||||
HT_AGG_STATE_OPERATIONAL;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
|
||||
ieee80211_stop_tx_ba_session(&sta->sta, tid,
|
||||
WLAN_BACK_RECIPIENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -659,7 +659,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
|
||||
sdata->dev->name, resp->da);
|
||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "key.h"
|
||||
|
@ -167,13 +168,10 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
|||
|
||||
struct ieee80211_rx_data {
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_key *key;
|
||||
struct ieee80211_rx_status *status;
|
||||
struct ieee80211_rate *rate;
|
||||
|
||||
unsigned int flags;
|
||||
int queue;
|
||||
|
@ -314,6 +312,8 @@ struct ieee80211_if_managed {
|
|||
} mfp; /* management frame protection */
|
||||
|
||||
int wmm_last_param_set;
|
||||
|
||||
u8 use_4addr;
|
||||
};
|
||||
|
||||
enum ieee80211_ibss_request {
|
||||
|
@ -461,8 +461,6 @@ struct ieee80211_sub_if_data {
|
|||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||
|
||||
bool use_4addr; /* use 4-address frames */
|
||||
|
||||
union {
|
||||
struct ieee80211_if_ap ap;
|
||||
struct ieee80211_if_wds wds;
|
||||
|
@ -581,7 +579,6 @@ struct ieee80211_local {
|
|||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
|
||||
unsigned int filter_flags; /* FIF_* */
|
||||
struct iw_statistics wstats;
|
||||
|
||||
/* protects the aggregated multicast list and filter calls */
|
||||
spinlock_t filter_lock;
|
||||
|
@ -771,8 +768,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
|
|||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
/* this struct represents 802.11n's RA/TID combination */
|
||||
/* this struct represents 802.11n's RA/TID combination along with our vif */
|
||||
struct ieee80211_ra_tid {
|
||||
struct ieee80211_vif *vif;
|
||||
u8 ra[ETH_ALEN];
|
||||
u16 tid;
|
||||
};
|
||||
|
@ -799,7 +797,7 @@ struct ieee802_11_elems {
|
|||
u8 *wmm_param;
|
||||
struct ieee80211_ht_cap *ht_cap_elem;
|
||||
struct ieee80211_ht_info *ht_info_elem;
|
||||
u8 *mesh_config;
|
||||
struct ieee80211_meshconf_ie *mesh_config;
|
||||
u8 *mesh_id;
|
||||
u8 *peer_link;
|
||||
u8 *preq;
|
||||
|
@ -827,7 +825,6 @@ struct ieee802_11_elems {
|
|||
u8 ext_supp_rates_len;
|
||||
u8 wmm_info_len;
|
||||
u8 wmm_param_len;
|
||||
u8 mesh_config_len;
|
||||
u8 mesh_id_len;
|
||||
u8 peer_link_len;
|
||||
u8 preq_len;
|
||||
|
@ -950,6 +947,18 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|||
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
|
||||
/*
|
||||
* radiotap header for status frames
|
||||
*/
|
||||
struct ieee80211_tx_status_rtap_hdr {
|
||||
struct ieee80211_radiotap_header hdr;
|
||||
u8 rate;
|
||||
u8 padding_for_rate;
|
||||
__le16 tx_flags;
|
||||
u8 data_retries;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* HT */
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_ht_cap *ht_cap_ie,
|
||||
|
@ -1017,8 +1026,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
|
|||
struct ieee80211_hdr *hdr, const u8 *tsc,
|
||||
gfp_t gfp);
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
|
||||
int encrypt);
|
||||
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
|
||||
void ieee802_11_parse_elems(u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems);
|
||||
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
|
||||
|
|
|
@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_mandatory_rates(sdata->local,
|
||||
sdata->local->hw.conf.channel->band);
|
||||
sdata->drop_unencrypted = 0;
|
||||
sdata->use_4addr = 0;
|
||||
if (type == NL80211_IFTYPE_STATION)
|
||||
sdata->u.mgd.use_4addr = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
/* setup type-dependent data */
|
||||
ieee80211_setup_sdata(sdata, type);
|
||||
|
||||
if (params) {
|
||||
ndev->ieee80211_ptr->use_4addr = params->use_4addr;
|
||||
if (type == NL80211_IFTYPE_STATION)
|
||||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
}
|
||||
|
||||
ret = register_netdevice(ndev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
params->mesh_id_len,
|
||||
params->mesh_id);
|
||||
|
||||
if (params && params->use_4addr >= 0)
|
||||
sdata->use_4addr = !!params->use_4addr;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_add_tail_rcu(&sdata->list, &local->interfaces);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
*/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
@ -30,26 +29,11 @@
|
|||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
#include "wep.h"
|
||||
#include "wme.h"
|
||||
#include "aes_ccm.h"
|
||||
#include "led.h"
|
||||
#include "cfg.h"
|
||||
#include "debugfs.h"
|
||||
#include "debugfs_netdev.h"
|
||||
|
||||
/*
|
||||
* For seeing transmitted packets on monitor interfaces
|
||||
* we have a radiotap header too.
|
||||
*/
|
||||
struct ieee80211_tx_status_rtap_hdr {
|
||||
struct ieee80211_radiotap_header hdr;
|
||||
u8 rate;
|
||||
u8 padding_for_rate;
|
||||
__le16 tx_flags;
|
||||
u8 data_retries;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
{
|
||||
u64 mc;
|
||||
|
@ -253,28 +237,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
|
|||
BSS_CHANGED_ERP_SLOT;
|
||||
}
|
||||
|
||||
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int tmp;
|
||||
|
||||
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
|
||||
skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
|
||||
&local->skb_queue : &local->skb_queue_unreliable, skb);
|
||||
tmp = skb_queue_len(&local->skb_queue) +
|
||||
skb_queue_len(&local->skb_queue_unreliable);
|
||||
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
|
||||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
|
||||
dev_kfree_skb_irq(skb);
|
||||
tmp--;
|
||||
I802_DEBUG_INC(local->tx_status_drop);
|
||||
}
|
||||
tasklet_schedule(&local->tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
|
||||
|
||||
static void ieee80211_tasklet_handler(unsigned long data)
|
||||
{
|
||||
struct ieee80211_local *local = (struct ieee80211_local *) data;
|
||||
|
@ -296,14 +258,14 @@ static void ieee80211_tasklet_handler(unsigned long data)
|
|||
break;
|
||||
case IEEE80211_DELBA_MSG:
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
ieee80211_stop_tx_ba_cb(local_to_hw(local),
|
||||
ra_tid->ra, ra_tid->tid);
|
||||
ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
|
||||
ra_tid->tid);
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case IEEE80211_ADDBA_MSG:
|
||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||
ieee80211_start_tx_ba_cb(local_to_hw(local),
|
||||
ra_tid->ra, ra_tid->tid);
|
||||
ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
|
||||
ra_tid->tid);
|
||||
dev_kfree_skb(skb);
|
||||
break ;
|
||||
default:
|
||||
|
@ -315,299 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
|
|||
}
|
||||
}
|
||||
|
||||
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
/*
|
||||
* XXX: This is temporary!
|
||||
*
|
||||
* The problem here is that when we get here, the driver will
|
||||
* quite likely have pretty much overwritten info->control by
|
||||
* using info->driver_data or info->rate_driver_data. Thus,
|
||||
* when passing out the frame to the driver again, we would be
|
||||
* passing completely bogus data since the driver would then
|
||||
* expect a properly filled info->control. In mac80211 itself
|
||||
* the same problem occurs, since we need info->control.vif
|
||||
* internally.
|
||||
*
|
||||
* To fix this, we should send the frame through TX processing
|
||||
* again. However, it's not that simple, since the frame will
|
||||
* have been software-encrypted (if applicable) already, and
|
||||
* encrypting it again doesn't do much good. So to properly do
|
||||
* that, we not only have to skip the actual 'raw' encryption
|
||||
* (key selection etc. still has to be done!) but also the
|
||||
* sequence number assignment since that impacts the crypto
|
||||
* encapsulation, of course.
|
||||
*
|
||||
* Hence, for now, fix the bug by just dropping the frame.
|
||||
*/
|
||||
goto drop;
|
||||
|
||||
sta->tx_filtered_count++;
|
||||
|
||||
/*
|
||||
* Clear the TX filter mask for this STA when sending the next
|
||||
* packet. If the STA went to power save mode, this will happen
|
||||
* when it wakes up for the next time.
|
||||
*/
|
||||
set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
|
||||
|
||||
/*
|
||||
* This code races in the following way:
|
||||
*
|
||||
* (1) STA sends frame indicating it will go to sleep and does so
|
||||
* (2) hardware/firmware adds STA to filter list, passes frame up
|
||||
* (3) hardware/firmware processes TX fifo and suppresses a frame
|
||||
* (4) we get TX status before having processed the frame and
|
||||
* knowing that the STA has gone to sleep.
|
||||
*
|
||||
* This is actually quite unlikely even when both those events are
|
||||
* processed from interrupts coming in quickly after one another or
|
||||
* even at the same time because we queue both TX status events and
|
||||
* RX frames to be processed by a tasklet and process them in the
|
||||
* same order that they were received or TX status last. Hence, there
|
||||
* is no race as long as the frame RX is processed before the next TX
|
||||
* status, which drivers can ensure, see below.
|
||||
*
|
||||
* Note that this can only happen if the hardware or firmware can
|
||||
* actually add STAs to the filter list, if this is done by the
|
||||
* driver in response to set_tim() (which will only reduce the race
|
||||
* this whole filtering tries to solve, not completely solve it)
|
||||
* this situation cannot happen.
|
||||
*
|
||||
* To completely solve this race drivers need to make sure that they
|
||||
* (a) don't mix the irq-safe/not irq-safe TX status/RX processing
|
||||
* functions and
|
||||
* (b) always process RX events before TX status events if ordering
|
||||
* can be unknown, for example with different interrupt status
|
||||
* bits.
|
||||
*/
|
||||
if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
|
||||
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
|
||||
skb_queue_tail(&sta->tx_filtered, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
|
||||
!(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
|
||||
/* Software retry the packet once */
|
||||
info->flags |= IEEE80211_TX_INTFL_RETRIED;
|
||||
ieee80211_add_pending_skb(local, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
drop:
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
|
||||
"queue_len=%d PS=%d @%lu\n",
|
||||
wiphy_name(local->hw.wiphy),
|
||||
skb_queue_len(&sta->tx_filtered),
|
||||
!!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
|
||||
#endif
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *skb2;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
u16 frag, type;
|
||||
__le16 fc;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_tx_status_rtap_hdr *rthdr;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct net_device *prev_dev = NULL;
|
||||
struct sta_info *sta;
|
||||
int retry_count = -1, i;
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
/* the HW cannot have attempted that rate */
|
||||
if (i >= hw->max_rates) {
|
||||
info->status.rates[i].idx = -1;
|
||||
info->status.rates[i].count = 0;
|
||||
}
|
||||
|
||||
retry_count += info->status.rates[i].count;
|
||||
}
|
||||
if (retry_count < 0)
|
||||
retry_count = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sband = local->hw.wiphy->bands[info->band];
|
||||
|
||||
sta = sta_info_get(local, hdr->addr1);
|
||||
|
||||
if (sta) {
|
||||
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
|
||||
test_sta_flags(sta, WLAN_STA_PS_STA)) {
|
||||
/*
|
||||
* The STA is in power save mode, so assume
|
||||
* that this TX packet failed because of that.
|
||||
*/
|
||||
ieee80211_handle_filtered_frame(local, sta, skb);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
|
||||
(ieee80211_is_data_qos(fc))) {
|
||||
u16 tid, ssn;
|
||||
u8 *qc;
|
||||
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & 0xf;
|
||||
ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
|
||||
& IEEE80211_SCTL_SEQ);
|
||||
ieee80211_send_bar(sta->sdata, hdr->addr1,
|
||||
tid, ssn);
|
||||
}
|
||||
|
||||
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
|
||||
ieee80211_handle_filtered_frame(local, sta, skb);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
} else {
|
||||
if (!(info->flags & IEEE80211_TX_STAT_ACK))
|
||||
sta->tx_retry_failed++;
|
||||
sta->tx_retry_count += retry_count;
|
||||
}
|
||||
|
||||
rate_control_tx_status(local, sband, sta, skb);
|
||||
if (ieee80211_vif_is_mesh(&sta->sdata->vif))
|
||||
ieee80211s_update_metric(local, sta, skb);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ieee80211_led_tx(local, 0);
|
||||
|
||||
/* SNMP counters
|
||||
* Fragments are passed to low-level drivers as separate skbs, so these
|
||||
* are actually fragments, not frames. Update frame counters only for
|
||||
* the first fragment of the frame. */
|
||||
|
||||
frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
|
||||
type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
|
||||
|
||||
if (info->flags & IEEE80211_TX_STAT_ACK) {
|
||||
if (frag == 0) {
|
||||
local->dot11TransmittedFrameCount++;
|
||||
if (is_multicast_ether_addr(hdr->addr1))
|
||||
local->dot11MulticastTransmittedFrameCount++;
|
||||
if (retry_count > 0)
|
||||
local->dot11RetryCount++;
|
||||
if (retry_count > 1)
|
||||
local->dot11MultipleRetryCount++;
|
||||
}
|
||||
|
||||
/* This counter shall be incremented for an acknowledged MPDU
|
||||
* with an individual address in the address 1 field or an MPDU
|
||||
* with a multicast address in the address 1 field of type Data
|
||||
* or Management. */
|
||||
if (!is_multicast_ether_addr(hdr->addr1) ||
|
||||
type == IEEE80211_FTYPE_DATA ||
|
||||
type == IEEE80211_FTYPE_MGMT)
|
||||
local->dot11TransmittedFragmentCount++;
|
||||
} else {
|
||||
if (frag == 0)
|
||||
local->dot11FailedCount++;
|
||||
}
|
||||
|
||||
/* this was a transmitted frame, but now we want to reuse it */
|
||||
skb_orphan(skb);
|
||||
|
||||
/*
|
||||
* This is a bit racy but we can avoid a lot of work
|
||||
* with this test...
|
||||
*/
|
||||
if (!local->monitors && !local->cooked_mntrs) {
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send frame to monitor interfaces now */
|
||||
|
||||
if (skb_headroom(skb) < sizeof(*rthdr)) {
|
||||
printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
rthdr = (struct ieee80211_tx_status_rtap_hdr *)
|
||||
skb_push(skb, sizeof(*rthdr));
|
||||
|
||||
memset(rthdr, 0, sizeof(*rthdr));
|
||||
rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
|
||||
rthdr->hdr.it_present =
|
||||
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
|
||||
(1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
|
||||
(1 << IEEE80211_RADIOTAP_RATE));
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
|
||||
!is_multicast_ether_addr(hdr->addr1))
|
||||
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
|
||||
|
||||
/*
|
||||
* XXX: Once radiotap gets the bitmap reset thing the vendor
|
||||
* extensions proposal contains, we can actually report
|
||||
* the whole set of tries we did.
|
||||
*/
|
||||
if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
||||
(info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
|
||||
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
|
||||
else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
||||
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
|
||||
if (info->status.rates[0].idx >= 0 &&
|
||||
!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
|
||||
rthdr->rate = sband->bitrates[
|
||||
info->status.rates[0].idx].bitrate / 5;
|
||||
|
||||
/* for now report the total retry_count */
|
||||
rthdr->data_retries = retry_count;
|
||||
|
||||
/* XXX: is this sufficient for BPF? */
|
||||
skb_set_mac_header(skb, 0);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
if (!netif_running(sdata->dev))
|
||||
continue;
|
||||
|
||||
if (prev_dev) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
skb2->dev = prev_dev;
|
||||
netif_rx(skb2);
|
||||
}
|
||||
}
|
||||
|
||||
prev_dev = sdata->dev;
|
||||
}
|
||||
}
|
||||
if (prev_dev) {
|
||||
skb->dev = prev_dev;
|
||||
netif_rx(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_status);
|
||||
|
||||
static void ieee80211_restart_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
|
@ -659,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
if (!wiphy)
|
||||
return NULL;
|
||||
|
||||
wiphy->netnsok = true;
|
||||
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
|
||||
WIPHY_FLAG_4ADDR_AP |
|
||||
WIPHY_FLAG_4ADDR_STATION;
|
||||
wiphy->privid = mac80211_wiphy_privid;
|
||||
|
||||
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
||||
|
|
|
@ -16,12 +16,6 @@
|
|||
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
||||
#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
|
||||
|
||||
#define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */
|
||||
#define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */
|
||||
#define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */
|
||||
#define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */
|
||||
#define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */
|
||||
#define MESHCONF_CAPAB_OFFSET 6
|
||||
#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
|
||||
#define MESHCONF_CAPAB_FORWARDING 0x08
|
||||
|
||||
|
@ -87,12 +81,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
|
|||
*/
|
||||
if (ifmsh->mesh_id_len == ie->mesh_id_len &&
|
||||
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
|
||||
(ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&&
|
||||
(ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&&
|
||||
(ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&&
|
||||
(ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&&
|
||||
(ifmsh->mesh_auth_id == *(ie->mesh_config +
|
||||
MESHCONF_AUTH_OFFSET)))
|
||||
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
|
||||
(ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
|
||||
(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
|
||||
(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
|
||||
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -105,7 +98,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
|
|||
*/
|
||||
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
|
||||
{
|
||||
return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) &
|
||||
return (ie->mesh_config->meshconf_cap &
|
||||
MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
|
||||
}
|
||||
|
||||
|
@ -262,9 +255,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
|||
if (sdata->u.mesh.mesh_id_len)
|
||||
memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
|
||||
|
||||
pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
|
||||
*pos++ = WLAN_EID_MESH_CONFIG;
|
||||
*pos++ = IEEE80211_MESH_CONFIG_LEN;
|
||||
*pos++ = sizeof(struct ieee80211_meshconf_ie);
|
||||
|
||||
/* Active path selection protocol ID */
|
||||
*pos++ = sdata->u.mesh.mesh_pp_id;
|
||||
|
@ -394,8 +387,9 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
|
|||
*
|
||||
* Return the length of the 802.11 (does not include a mesh control header)
|
||||
*/
|
||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
|
||||
*meshda, char *meshsa) {
|
||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
const u8 *meshda, const u8 *meshsa)
|
||||
{
|
||||
if (is_multicast_ether_addr(meshda)) {
|
||||
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA TA SA */
|
||||
|
|
|
@ -220,7 +220,7 @@ struct mesh_rmc {
|
|||
/* Public interfaces */
|
||||
/* Various */
|
||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||
char *da, char *sa);
|
||||
const u8 *da, const u8 *sa);
|
||||
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
|
||||
struct ieee80211_sub_if_data *sdata, char *addr4,
|
||||
char *addr5, char *addr6);
|
||||
|
@ -284,7 +284,7 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
|
|||
struct mesh_table *tbl);
|
||||
/* Mesh paths */
|
||||
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode,
|
||||
u8 *ra, struct ieee80211_sub_if_data *sdata);
|
||||
const u8 *ra, struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
|
||||
void mesh_path_flush_pending(struct mesh_path *mpath);
|
||||
void mesh_path_tx_pending(struct mesh_path *mpath);
|
||||
|
|
|
@ -101,10 +101,12 @@ enum mpath_frame_type {
|
|||
MPATH_RANN
|
||||
};
|
||||
|
||||
static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||
u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
|
||||
__le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime,
|
||||
__le32 metric, __le32 preq_id,
|
||||
__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
|
||||
__le32 lifetime, __le32 metric, __le32 preq_id,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
@ -185,7 +187,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
|||
memcpy(pos, &target_sn, 4);
|
||||
}
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -198,8 +200,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
|||
* @ra: node this frame is addressed to
|
||||
*/
|
||||
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
||||
__le16 target_rcode, u8 *ra,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
__le16 target_rcode, const u8 *ra,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
|
||||
|
@ -248,7 +250,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
|||
pos += 4;
|
||||
memcpy(pos, &target_rcode, 2);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 1);
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -548,7 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
|
|||
hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
|
||||
mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
|
||||
cpu_to_le32(orig_sn), target_flags, target_addr,
|
||||
cpu_to_le32(target_sn), sdata->dev->broadcast,
|
||||
cpu_to_le32(target_sn), broadcast_addr,
|
||||
hopcount, ttl, cpu_to_le32(lifetime),
|
||||
cpu_to_le32(metric), cpu_to_le32(preq_id),
|
||||
sdata);
|
||||
|
@ -660,7 +662,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
|
|||
spin_unlock_bh(&mpath->state_lock);
|
||||
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
|
||||
cpu_to_le16(target_rcode),
|
||||
sdata->dev->broadcast, sdata);
|
||||
broadcast_addr, sdata);
|
||||
} else
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
}
|
||||
|
@ -709,7 +711,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
|||
if (mpath->sn < orig_sn) {
|
||||
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
|
||||
cpu_to_le32(orig_sn),
|
||||
0, NULL, 0, sdata->dev->broadcast,
|
||||
0, NULL, 0, broadcast_addr,
|
||||
hopcount, ttl, 0,
|
||||
cpu_to_le32(metric + mpath->metric),
|
||||
0, sdata);
|
||||
|
@ -890,7 +892,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
|
|||
spin_unlock_bh(&mpath->state_lock);
|
||||
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
|
||||
cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
|
||||
cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0,
|
||||
cpu_to_le32(mpath->sn), broadcast_addr, 0,
|
||||
ttl, cpu_to_le32(lifetime), 0,
|
||||
cpu_to_le32(ifmsh->preq_id++), sdata);
|
||||
mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
|
||||
|
@ -1011,6 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
|
||||
cpu_to_le32(++ifmsh->sn),
|
||||
0, NULL, 0, sdata->dev->broadcast,
|
||||
0, NULL, 0, broadcast_addr,
|
||||
0, MESH_TTL, 0, 0, 0, sdata);
|
||||
}
|
||||
|
|
|
@ -449,6 +449,7 @@ err_path_alloc:
|
|||
*/
|
||||
void mesh_plink_broken(struct sta_info *sta)
|
||||
{
|
||||
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
struct mesh_path *mpath;
|
||||
struct mpath_node *node;
|
||||
struct hlist_node *p;
|
||||
|
@ -467,8 +468,8 @@ void mesh_plink_broken(struct sta_info *sta)
|
|||
spin_unlock_bh(&mpath->state_lock);
|
||||
mesh_path_error_tx(MESH_TTL, mpath->dst,
|
||||
cpu_to_le32(mpath->sn),
|
||||
PERR_RCODE_DEST_UNREACH,
|
||||
sdata->dev->broadcast, sdata);
|
||||
cpu_to_le16(PERR_RCODE_DEST_UNREACH),
|
||||
bcast, sdata);
|
||||
} else
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
}
|
||||
|
@ -613,7 +614,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
|
|||
if (mpath)
|
||||
sn = ++mpath->sn;
|
||||
mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn),
|
||||
PERR_RCODE_NO_ROUTE, ra, sdata);
|
||||
cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue