mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 00:51:35 +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;
|
break;
|
||||||
|
|
||||||
|
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||||
switch (head->plcp[0] & 0xf) {
|
switch (head->plcp[0] & 0xf) {
|
||||||
case 0xb:
|
case 0xb:
|
||||||
|
@ -897,8 +898,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
|
||||||
status->flag |= RX_FLAG_HT;
|
status->flag |= RX_FLAG_HT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
default:
|
||||||
/* XXX */
|
|
||||||
if (ar9170_nag_limiter(ar))
|
if (ar9170_nag_limiter(ar))
|
||||||
printk(KERN_ERR "%s: invalid modulation\n",
|
printk(KERN_ERR "%s: invalid modulation\n",
|
||||||
wiphy_name(ar->hw->wiphy));
|
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,
|
static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
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->state = AR9170_TID_STATE_PROGRESS;
|
||||||
tid_info->active = false;
|
tid_info->active = false;
|
||||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
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;
|
break;
|
||||||
|
|
||||||
case IEEE80211_AMPDU_TX_STOP:
|
case IEEE80211_AMPDU_TX_STOP:
|
||||||
|
@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||||
tid_info->active = false;
|
tid_info->active = false;
|
||||||
skb_queue_purge(&tid_info->queue);
|
skb_queue_purge(&tid_info->queue);
|
||||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
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;
|
break;
|
||||||
|
|
||||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||||
|
|
|
@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
||||||
{ USB_DEVICE(0x0cf3, 0x1002) },
|
{ USB_DEVICE(0x0cf3, 0x1002) },
|
||||||
/* Cace Airpcap NX */
|
/* Cace Airpcap NX */
|
||||||
{ USB_DEVICE(0xcace, 0x0300) },
|
{ USB_DEVICE(0xcace, 0x0300) },
|
||||||
/* D-Link DWA 160A */
|
/* D-Link DWA 160 A1 */
|
||||||
{ USB_DEVICE(0x07d1, 0x3c10) },
|
{ USB_DEVICE(0x07d1, 0x3c10) },
|
||||||
|
/* D-Link DWA 160 A2 */
|
||||||
|
{ USB_DEVICE(0x07d1, 0x3a09) },
|
||||||
/* Netgear WNDA3100 */
|
/* Netgear WNDA3100 */
|
||||||
{ USB_DEVICE(0x0846, 0x9010) },
|
{ USB_DEVICE(0x0846, 0x9010) },
|
||||||
/* Netgear WN111 v2 */
|
/* Netgear WN111 v2 */
|
||||||
|
|
|
@ -1399,7 +1399,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
||||||
if (i_coffd == 0 || q_coffd == 0)
|
if (i_coffd == 0 || q_coffd == 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
i_coff = ((-iq_corr) / i_coffd) & 0x3f;
|
i_coff = ((-iq_corr) / i_coffd);
|
||||||
|
|
||||||
/* Boundary check */
|
/* Boundary check */
|
||||||
if (i_coff > 31)
|
if (i_coff > 31)
|
||||||
|
@ -1407,7 +1407,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
||||||
if (i_coff < -32)
|
if (i_coff < -32)
|
||||||
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 */
|
/* Boundary check */
|
||||||
if (q_coff > 15)
|
if (q_coff > 15)
|
||||||
|
|
|
@ -198,18 +198,8 @@ struct ath_txq {
|
||||||
struct list_head axq_q;
|
struct list_head axq_q;
|
||||||
spinlock_t axq_lock;
|
spinlock_t axq_lock;
|
||||||
u32 axq_depth;
|
u32 axq_depth;
|
||||||
u8 axq_aggr_depth;
|
|
||||||
bool stopped;
|
bool stopped;
|
||||||
bool axq_tx_inprogress;
|
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;
|
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 ath_hw *ah = common->ah;
|
||||||
struct ieee80211_hdr *hdr;
|
struct ieee80211_hdr *hdr;
|
||||||
int hdrlen, padsize;
|
int hdrlen, padpos, padsize;
|
||||||
u8 keyix;
|
u8 keyix;
|
||||||
__le16 fc;
|
__le16 fc;
|
||||||
|
|
||||||
/* see if any padding is done by the hw and remove it */
|
/* see if any padding is done by the hw and remove it */
|
||||||
hdr = (struct ieee80211_hdr *) skb->data;
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||||
|
padpos = 24;
|
||||||
fc = hdr->frame_control;
|
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
|
/* The MAC header is padded to have 32-bit boundary if the
|
||||||
* packet payload is non-zero. The general calculation for
|
* packet payload is non-zero. The general calculation for
|
||||||
* padsize would take into account odd header lengths:
|
* 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
|
* even-length headers are used, padding can only be 0 or 2
|
||||||
* bytes and we can optimize this a bit. In addition, we must
|
* bytes and we can optimize this a bit. In addition, we must
|
||||||
* not try to remove padding from short control frames that do
|
* not try to remove padding from short control frames that do
|
||||||
* not have payload. */
|
* not have payload. */
|
||||||
padsize = hdrlen & 3;
|
padsize = padpos & 3;
|
||||||
if (padsize && hdrlen >= 24) {
|
if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
|
||||||
memmove(skb->data + padsize, skb->data, hdrlen);
|
memmove(skb->data + padsize, skb->data, padpos);
|
||||||
skb_pull(skb, padsize);
|
skb_pull(skb, padsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct ath_buf {
|
||||||
u16 bf_flags;
|
u16 bf_flags;
|
||||||
struct ath_buf_state bf_state;
|
struct ath_buf_state bf_state;
|
||||||
dma_addr_t bf_dmacontext;
|
dma_addr_t bf_dmacontext;
|
||||||
|
struct ath_wiphy *aphy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath_atx_tid {
|
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)
|
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_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
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;
|
struct ath_rc_stats *stats;
|
||||||
|
|
||||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
if (!rates[i].count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
final_ts_idx = i;
|
||||||
|
}
|
||||||
idx = rates[final_ts_idx].idx;
|
idx = rates[final_ts_idx].idx;
|
||||||
stats = &sc->debug.stats.rcstats[idx];
|
stats = &sc->debug.stats.rcstats[idx];
|
||||||
stats->success++;
|
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_high = 200;
|
||||||
ah->config.cck_trig_low = 100;
|
ah->config.cck_trig_low = 100;
|
||||||
ah->config.enable_ani = 1;
|
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++) {
|
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
||||||
ah->config.spurchans[i][0] = AR_NO_SPUR;
|
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->acktimeout = (u32) -1;
|
||||||
ah->ctstimeout = (u32) -1;
|
ah->ctstimeout = (u32) -1;
|
||||||
ah->globaltxtimeout = (u32) -1;
|
ah->globaltxtimeout = (u32) -1;
|
||||||
|
|
||||||
ah->gbeacon_rate = 0;
|
|
||||||
|
|
||||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
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,
|
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
|
||||||
AR_PHY_SWAP_ALT_CHAIN);
|
AR_PHY_SWAP_ALT_CHAIN);
|
||||||
case 0x3:
|
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_RX_CHAINMASK, 0x7);
|
||||||
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
|
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
|
||||||
break;
|
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->ath9k_hw_spur_mitigate_freq(ah, chan);
|
||||||
ah->eep_ops->set_board_values(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_ID0, get_unaligned_le32(common->macaddr));
|
||||||
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
|
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
|
||||||
| macStaId1
|
| macStaId1
|
||||||
|
@ -3518,51 +3510,6 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ath9k_hw_setantenna);
|
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 */
|
/* General Operation */
|
||||||
/*********************/
|
/*********************/
|
||||||
|
|
|
@ -148,21 +148,6 @@ enum wireless_mode {
|
||||||
ATH9K_MODE_MAX,
|
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 {
|
enum ath9k_hw_caps {
|
||||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
||||||
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
||||||
|
@ -226,8 +211,6 @@ struct ath9k_ops_config {
|
||||||
u32 cck_trig_high;
|
u32 cck_trig_high;
|
||||||
u32 cck_trig_low;
|
u32 cck_trig_low;
|
||||||
u32 enable_ani;
|
u32 enable_ani;
|
||||||
enum ath9k_ant_setting diversity_control;
|
|
||||||
u16 antenna_switch_swap;
|
|
||||||
int serialize_regmode;
|
int serialize_regmode;
|
||||||
bool intr_mitigation;
|
bool intr_mitigation;
|
||||||
#define SPUR_DISABLE 0
|
#define SPUR_DISABLE 0
|
||||||
|
@ -572,7 +555,6 @@ struct ath_hw {
|
||||||
u32 acktimeout;
|
u32 acktimeout;
|
||||||
u32 ctstimeout;
|
u32 ctstimeout;
|
||||||
u32 globaltxtimeout;
|
u32 globaltxtimeout;
|
||||||
u8 gbeacon_rate;
|
|
||||||
|
|
||||||
/* ANI */
|
/* ANI */
|
||||||
u32 proc_phyerr;
|
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);
|
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
|
||||||
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
|
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
|
||||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
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 */
|
/* General Operation */
|
||||||
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
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_ADHOC) |
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||||
|
|
||||||
|
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||||
|
|
||||||
hw->queues = 4;
|
hw->queues = 4;
|
||||||
hw->max_rates = 4;
|
hw->max_rates = 4;
|
||||||
hw->channel_change_time = 5000;
|
hw->channel_change_time = 5000;
|
||||||
|
@ -2956,33 +2958,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||||
u32 rfilt = 0;
|
int error;
|
||||||
int error, i;
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
mutex_lock(&sc->mutex);
|
||||||
|
|
||||||
/*
|
if (changed & BSS_CHANGED_BSSID) {
|
||||||
* 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);
|
|
||||||
common->curaid = 0;
|
|
||||||
ath9k_hw_write_associd(ah);
|
|
||||||
/* Request full reset to get hw opmode changed properly */
|
|
||||||
sc->sc_flags |= SC_OP_FULL_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
/* Set BSSID */
|
||||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||||
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
||||||
|
@ -2992,53 +2972,47 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
/* Set aggregation protection mode parameters */
|
/* Set aggregation protection mode parameters */
|
||||||
sc->config.ath_aggr_prot = 0;
|
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,
|
ath_print(common, ATH_DBG_CONFIG,
|
||||||
"RX filter 0x%x bssid %pM aid 0x%x\n",
|
"BSSID: %pM aid: 0x%x\n",
|
||||||
rfilt, common->curbssid, common->curaid);
|
common->curbssid, common->curaid);
|
||||||
|
|
||||||
/* need to reconfigure the beacon */
|
/* need to reconfigure the beacon */
|
||||||
sc->sc_flags &= ~SC_OP_BEACONS ;
|
sc->sc_flags &= ~SC_OP_BEACONS ;
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vif->type == NL80211_IFTYPE_ADHOC) ||
|
/* Enable transmission of beacons (AP, IBSS, MESH) */
|
||||||
(vif->type == NL80211_IFTYPE_AP) ||
|
|
||||||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
|
|
||||||
if ((changed & BSS_CHANGED_BEACON) ||
|
if ((changed & BSS_CHANGED_BEACON) ||
|
||||||
(changed & BSS_CHANGED_BEACON_ENABLED &&
|
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
|
||||||
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.
|
|
||||||
*/
|
|
||||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||||
|
|
||||||
error = ath_beacon_alloc(aphy, vif);
|
error = ath_beacon_alloc(aphy, vif);
|
||||||
if (!error)
|
if (!error)
|
||||||
ath_beacon_config(sc, vif);
|
ath_beacon_config(sc, vif);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for WLAN_CAPABILITY_PRIVACY ? */
|
/* Disable transmission of beacons */
|
||||||
if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
|
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
|
||||||
for (i = 0; i < IEEE80211_WEP_NKID; i++)
|
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||||
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 (changed & BSS_CHANGED_BEACON_INT) {
|
||||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
sc->beacon_interval = bss_conf->beacon_int;
|
||||||
ath_update_chainmask(sc, 0);
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
||||||
ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
|
ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
|
||||||
|
@ -3065,18 +3039,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
ath9k_bss_assoc_info(sc, vif, bss_conf);
|
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);
|
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,
|
static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
u16 tid, u16 *ssn)
|
u16 tid, u16 *ssn)
|
||||||
|
@ -3135,11 +3098,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||||
break;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_START:
|
case IEEE80211_AMPDU_TX_START:
|
||||||
ath_tx_aggr_start(sc, sta, tid, ssn);
|
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;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_STOP:
|
case IEEE80211_AMPDU_TX_STOP:
|
||||||
ath_tx_aggr_stop(sc, sta, tid);
|
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;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||||
ath_tx_aggr_resume(sc, sta, tid);
|
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);
|
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
|
* ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
|
||||||
* @ah: atheros hardware stucture
|
* @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_force_bias(ah, freq);
|
||||||
ath9k_hw_decrease_chain_power(ah, chan);
|
|
||||||
|
|
||||||
reg32 =
|
reg32 =
|
||||||
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
|
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
|
||||||
|
|
|
@ -35,9 +35,6 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
|
||||||
struct ath9k_channel *chan,
|
struct ath9k_channel *chan,
|
||||||
u16 modesIndex);
|
u16 modesIndex);
|
||||||
|
|
||||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
|
||||||
struct ath9k_channel *chan);
|
|
||||||
|
|
||||||
#define AR_PHY_BASE 0x9800
|
#define AR_PHY_BASE 0x9800
|
||||||
#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
|
#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,
|
static bool ath_rc_update_per(struct ath_softc *sc,
|
||||||
const struct ath_rate_table *rate_table,
|
const struct ath_rate_table *rate_table,
|
||||||
struct ath_rate_priv *ath_rc_priv,
|
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,
|
int tx_rate, int xretries, int retries,
|
||||||
u32 now_msec)
|
u32 now_msec)
|
||||||
{
|
{
|
||||||
bool state_change = false;
|
bool state_change = false;
|
||||||
int count;
|
int count, n_bad_frames;
|
||||||
u8 last_per;
|
u8 last_per;
|
||||||
static u32 nretry_to_per_lookup[10] = {
|
static u32 nretry_to_per_lookup[10] = {
|
||||||
100 * 0 / 1,
|
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];
|
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) {
|
||||||
if (xretries == 1) {
|
if (xretries == 1) {
|
||||||
|
@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||||
if (retries >= count)
|
if (retries >= count)
|
||||||
retries = count - 1;
|
retries = count - 1;
|
||||||
|
|
||||||
if (tx_info_priv->n_bad_frames) {
|
if (n_bad_frames) {
|
||||||
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
|
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
|
||||||
* Assuming that n_frames is not 0. The current PER
|
* Assuming that n_frames is not 0. The current PER
|
||||||
* from the retries is 100 * retries / (retries+1),
|
* 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
|
* the above PER. The expression below is a
|
||||||
* simplified version of the sum of these two terms.
|
* simplified version of the sum of these two terms.
|
||||||
*/
|
*/
|
||||||
if (tx_info_priv->n_frames > 0) {
|
if (tx_info->status.ampdu_len > 0) {
|
||||||
int n_frames, n_bad_frames;
|
int n_frames, n_bad_tries;
|
||||||
u8 cur_per, new_per;
|
u8 cur_per, new_per;
|
||||||
|
|
||||||
n_bad_frames = retries * tx_info_priv->n_frames +
|
n_bad_tries = retries * tx_info->status.ampdu_len +
|
||||||
tx_info_priv->n_bad_frames;
|
n_bad_frames;
|
||||||
n_frames = tx_info_priv->n_frames * (retries + 1);
|
n_frames = tx_info->status.ampdu_len * (retries + 1);
|
||||||
cur_per = (100 * n_bad_frames / n_frames) >> 3;
|
cur_per = (100 * n_bad_tries / n_frames) >> 3;
|
||||||
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
|
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
|
||||||
ath_rc_priv->per[tx_rate] = new_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.
|
* this was a probe. Otherwise, ignore the probe.
|
||||||
*/
|
*/
|
||||||
if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
|
if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
|
||||||
if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
|
if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) {
|
||||||
tx_info_priv->n_frames) {
|
|
||||||
/*
|
/*
|
||||||
* Since we probed with just a single attempt,
|
* Since we probed with just a single attempt,
|
||||||
* any retries means the probe failed. Also,
|
* 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,
|
static void ath_rc_update_ht(struct ath_softc *sc,
|
||||||
struct ath_rate_priv *ath_rc_priv,
|
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)
|
int tx_rate, int xretries, int retries)
|
||||||
{
|
{
|
||||||
u32 now_msec = jiffies_to_msecs(jiffies);
|
u32 now_msec = jiffies_to_msecs(jiffies);
|
||||||
|
@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
|
||||||
|
|
||||||
/* Update PER first */
|
/* Update PER first */
|
||||||
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
|
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);
|
retries, now_msec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||||
struct ieee80211_tx_info *tx_info,
|
struct ieee80211_tx_info *tx_info,
|
||||||
int final_ts_idx, int xretries, int long_retry)
|
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;
|
const struct ath_rate_table *rate_table;
|
||||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
|
@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||||
ath_rc_update_ht(sc, ath_rc_priv,
|
ath_rc_update_ht(sc, ath_rc_priv, tx_info,
|
||||||
tx_info_priv, rix,
|
rix, xretries ? 1 : 2,
|
||||||
xretries ? 1 : 2,
|
|
||||||
rates[i].count);
|
rates[i].count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
|
ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
|
||||||
xretries, long_retry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const
|
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_softc *sc = priv;
|
||||||
struct ath_rate_priv *ath_rc_priv = priv_sta;
|
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_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_hdr *hdr;
|
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;
|
__le16 fc;
|
||||||
|
int i;
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *)skb->data;
|
hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
fc = hdr->frame_control;
|
fc = hdr->frame_control;
|
||||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
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) ||
|
if (!priv_sta || !ieee80211_is_data(fc) ||
|
||||||
!tx_info_priv->update_rc)
|
!(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC))
|
||||||
goto exit;
|
return;
|
||||||
|
|
||||||
if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
|
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
|
||||||
goto exit;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If underrun error is seen assume it as an excessive retry only
|
* 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
|
* 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.
|
* times. This affects how ratectrl updates PER for the failed rate.
|
||||||
*/
|
*/
|
||||||
if (tx_info_priv->tx.ts_flags &
|
if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
|
||||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
|
(sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
|
||||||
((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
|
|
||||||
tx_status = 1;
|
tx_status = 1;
|
||||||
is_underrun = 1;
|
is_underrun = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
|
if (tx_info->pad[0] & ATH_TX_INFO_XRETRY)
|
||||||
(tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
|
|
||||||
tx_status = 1;
|
tx_status = 1;
|
||||||
|
|
||||||
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
|
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
|
||||||
(is_underrun) ? sc->hw->max_rate_tries :
|
(is_underrun) ? sc->hw->max_rate_tries : long_retry);
|
||||||
tx_info_priv->tx.ts_longretry);
|
|
||||||
|
|
||||||
/* Check if aggregation has to be enabled for this tid */
|
/* Check if aggregation has to be enabled for this tid */
|
||||||
if (conf_is_ht(&sc->hw->conf) &&
|
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;
|
an = (struct ath_node *)sta->drv_priv;
|
||||||
|
|
||||||
if(ath_tx_aggr_check(sc, an, tid))
|
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);
|
ath_debug_stat_rc(sc, skb);
|
||||||
exit:
|
|
||||||
kfree(tx_info_priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
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;
|
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 {
|
enum ath9k_internal_frame_type {
|
||||||
ATH9K_NOT_INTERNAL,
|
ATH9K_NOT_INTERNAL,
|
||||||
ATH9K_INT_PAUSE,
|
ATH9K_INT_PAUSE,
|
||||||
ATH9K_INT_UNPAUSE
|
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);
|
void ath_rate_attach(struct ath_softc *sc);
|
||||||
u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
|
u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
|
||||||
int ath_rate_control_register(void);
|
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)
|
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ath_wiphy *aphy = hw->priv;
|
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 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) {
|
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 "
|
printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
|
||||||
"frame\n", wiphy_name(hw->wiphy));
|
"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);
|
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);
|
ATH_TXBUF_RESET(tbf);
|
||||||
|
|
||||||
|
tbf->aphy = bf->aphy;
|
||||||
tbf->bf_mpdu = bf->bf_mpdu;
|
tbf->bf_mpdu = bf->bf_mpdu;
|
||||||
tbf->bf_buf_addr = bf->bf_buf_addr;
|
tbf->bf_buf_addr = bf->bf_buf_addr;
|
||||||
*(tbf->bf_desc) = *(bf->bf_desc);
|
*(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_hw *hw;
|
||||||
struct ieee80211_hdr *hdr;
|
struct ieee80211_hdr *hdr;
|
||||||
struct ieee80211_tx_info *tx_info;
|
struct ieee80211_tx_info *tx_info;
|
||||||
struct ath_tx_info_priv *tx_info_priv;
|
|
||||||
struct ath_atx_tid *tid = NULL;
|
struct ath_atx_tid *tid = NULL;
|
||||||
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
|
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
|
||||||
struct ath_desc *ds = bf_last->bf_desc;
|
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;
|
hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
|
|
||||||
tx_info = IEEE80211_SKB_CB(skb);
|
tx_info = IEEE80211_SKB_CB(skb);
|
||||||
tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
|
hw = bf->aphy->hw;
|
||||||
hw = tx_info_priv->aphy->hw;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
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 sk_buff *skb;
|
||||||
struct ieee80211_tx_info *tx_info;
|
struct ieee80211_tx_info *tx_info;
|
||||||
struct ieee80211_tx_rate *rates;
|
struct ieee80211_tx_rate *rates;
|
||||||
struct ath_tx_info_priv *tx_info_priv;
|
|
||||||
u32 max_4ms_framelen, frmlen;
|
u32 max_4ms_framelen, frmlen;
|
||||||
u16 aggr_limit, legacy = 0;
|
u16 aggr_limit, legacy = 0;
|
||||||
int i;
|
int i;
|
||||||
|
@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
||||||
skb = bf->bf_mpdu;
|
skb = bf->bf_mpdu;
|
||||||
tx_info = IEEE80211_SKB_CB(skb);
|
tx_info = IEEE80211_SKB_CB(skb);
|
||||||
rates = tx_info->control.rates;
|
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
|
* 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 */
|
/* anchor last desc of aggregate */
|
||||||
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
|
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
|
||||||
|
|
||||||
txq->axq_aggr_depth++;
|
|
||||||
ath_tx_txqaddbuf(sc, txq, &bf_q);
|
ath_tx_txqaddbuf(sc, txq, &bf_q);
|
||||||
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
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);
|
INIT_LIST_HEAD(&txq->axq_acq);
|
||||||
spin_lock_init(&txq->axq_lock);
|
spin_lock_init(&txq->axq_lock);
|
||||||
txq->axq_depth = 0;
|
txq->axq_depth = 0;
|
||||||
txq->axq_aggr_depth = 0;
|
|
||||||
txq->axq_linkbuf = NULL;
|
|
||||||
txq->axq_tx_inprogress = false;
|
txq->axq_tx_inprogress = false;
|
||||||
sc->tx.txqsetup |= 1<<qnum;
|
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)) {
|
if (list_empty(&txq->axq_q)) {
|
||||||
txq->axq_link = NULL;
|
txq->axq_link = NULL;
|
||||||
txq->axq_linkbuf = NULL;
|
|
||||||
spin_unlock_bh(&txq->axq_lock);
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
break;
|
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);
|
list_splice_tail_init(head, &txq->axq_q);
|
||||||
txq->axq_depth++;
|
txq->axq_depth++;
|
||||||
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
|
|
||||||
|
|
||||||
ath_print(common, ATH_DBG_QUEUE,
|
ath_print(common, ATH_DBG_QUEUE,
|
||||||
"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
|
"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 ath_softc *sc = aphy->sc;
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
struct ath_tx_info_priv *tx_info_priv;
|
|
||||||
int hdrlen;
|
int hdrlen;
|
||||||
__le16 fc;
|
__le16 fc;
|
||||||
|
|
||||||
tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
|
tx_info->pad[0] = 0;
|
||||||
if (unlikely(!tx_info_priv))
|
switch (txctl->frame_type) {
|
||||||
return -ENOMEM;
|
case ATH9K_NOT_INTERNAL:
|
||||||
tx_info->rate_driver_data[0] = tx_info_priv;
|
break;
|
||||||
tx_info_priv->aphy = aphy;
|
case ATH9K_INT_PAUSE:
|
||||||
tx_info_priv->frame_type = txctl->frame_type;
|
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);
|
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||||
fc = hdr->frame_control;
|
fc = hdr->frame_control;
|
||||||
|
|
||||||
ATH_TXBUF_RESET(bf);
|
ATH_TXBUF_RESET(bf);
|
||||||
|
|
||||||
|
bf->aphy = aphy;
|
||||||
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
|
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
|
||||||
|
|
||||||
if (conf_is_ht(&hw->conf) && !is_pae(skb))
|
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);
|
skb->len, DMA_TO_DEVICE);
|
||||||
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
|
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
|
||||||
bf->bf_mpdu = NULL;
|
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,
|
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
|
||||||
"dma_mapping_error() on TX\n");
|
"dma_mapping_error() on TX\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1781,27 +1776,17 @@ exit:
|
||||||
/*****************/
|
/*****************/
|
||||||
|
|
||||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
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_hw *hw = sc->hw;
|
||||||
struct ieee80211_tx_info *tx_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);
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
int hdrlen, padsize;
|
int hdrlen, padsize;
|
||||||
int frame_type = ATH9K_NOT_INTERNAL;
|
|
||||||
|
|
||||||
ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
|
ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
|
||||||
|
|
||||||
if (tx_info_priv) {
|
if (aphy)
|
||||||
hw = tx_info_priv->aphy->hw;
|
hw = 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 (tx_flags & ATH_TX_BAR)
|
if (tx_flags & ATH_TX_BAR)
|
||||||
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
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));
|
SC_OP_WAIT_FOR_TX_ACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_type == ATH9K_NOT_INTERNAL)
|
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
|
||||||
ieee80211_tx_status(hw, skb);
|
|
||||||
else
|
|
||||||
ath9k_tx_status(hw, skb);
|
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,
|
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);
|
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);
|
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 sk_buff *skb = bf->bf_mpdu;
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
struct ieee80211_tx_info *tx_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);
|
struct ieee80211_hw *hw = bf->aphy->hw;
|
||||||
struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
|
|
||||||
u8 i, tx_rateindex;
|
u8 i, tx_rateindex;
|
||||||
|
|
||||||
if (txok)
|
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;
|
tx_rateindex = ds->ds_txstat.ts_rateindex;
|
||||||
WARN_ON(tx_rateindex >= hw->max_rates);
|
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)
|
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
|
||||||
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
||||||
|
|
||||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
||||||
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
||||||
if (ieee80211_is_data(hdr->frame_control)) {
|
if (ieee80211_is_data(hdr->frame_control)) {
|
||||||
memcpy(&tx_info_priv->tx, &ds->ds_txstat,
|
if (ds->ds_txstat.ts_flags &
|
||||||
sizeof(tx_info_priv->tx));
|
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
|
||||||
tx_info_priv->n_frames = bf->bf_nframes;
|
tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
|
||||||
tx_info_priv->n_bad_frames = nbad;
|
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);
|
spin_lock_bh(&txq->axq_lock);
|
||||||
if (list_empty(&txq->axq_q)) {
|
if (list_empty(&txq->axq_q)) {
|
||||||
txq->axq_link = NULL;
|
txq->axq_link = NULL;
|
||||||
txq->axq_linkbuf = NULL;
|
|
||||||
spin_unlock_bh(&txq->axq_lock);
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2005,10 +1993,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||||
spin_unlock_bh(&txq->axq_lock);
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
break;
|
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,
|
* 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_q, lastbf->list.prev);
|
||||||
|
|
||||||
txq->axq_depth--;
|
txq->axq_depth--;
|
||||||
if (bf_isaggr(bf))
|
|
||||||
txq->axq_aggr_depth--;
|
|
||||||
|
|
||||||
txok = (ds->ds_txstat.ts_status == 0);
|
txok = (ds->ds_txstat.ts_status == 0);
|
||||||
txq->axq_tx_inprogress = false;
|
txq->axq_tx_inprogress = false;
|
||||||
spin_unlock_bh(&txq->axq_lock);
|
spin_unlock_bh(&txq->axq_lock);
|
||||||
|
|
|
@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
||||||
const struct ieee80211_regdomain *regd;
|
const struct ieee80211_regdomain *regd;
|
||||||
|
|
||||||
wiphy->reg_notifier = reg_notifier;
|
wiphy->reg_notifier = reg_notifier;
|
||||||
wiphy->strict_regulatory = true;
|
wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||||
|
|
||||||
if (ath_is_world_regd(reg)) {
|
if (ath_is_world_regd(reg)) {
|
||||||
/*
|
/*
|
||||||
|
@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
||||||
* saved on the wiphy orig_* parameters
|
* saved on the wiphy orig_* parameters
|
||||||
*/
|
*/
|
||||||
regd = ath_world_regdomain(reg);
|
regd = ath_world_regdomain(reg);
|
||||||
wiphy->custom_regulatory = true;
|
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy->strict_regulatory = false;
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* This gets applied in the case of the absense of CRDA,
|
* 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)
|
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
|
/* There are several requirements to the descriptor ring memory:
|
||||||
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
|
* - The memory region needs to fit the address constraints for the
|
||||||
* has shown that 4K is sufficient for the latter as long as the buffer
|
* device (same as for frame buffers).
|
||||||
* does not cross an 8K boundary.
|
* - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
|
||||||
*
|
* - For 64bit DMA devices, the descriptor ring must be 8k aligned.
|
||||||
* 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!
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ring->type == B43_DMA_64BIT)
|
if (ring->type == B43_DMA_64BIT)
|
||||||
flags |= GFP_DMA;
|
required = ring->nr_slots * sizeof(struct b43_dmadesc64);
|
||||||
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
|
else
|
||||||
B43_DMA_RINGMEMSIZE,
|
required = ring->nr_slots * sizeof(struct b43_dmadesc32);
|
||||||
&(ring->dmabase), flags);
|
if (B43_WARN_ON(required > 0x1000))
|
||||||
if (!ring->descbase) {
|
|
||||||
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
|
|
||||||
return -ENOMEM;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_ringmemory(struct b43_dmaring *ring)
|
static void free_ringmemory(struct b43_dmaring *ring)
|
||||||
{
|
{
|
||||||
gfp_t flags = GFP_KERNEL;
|
b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
|
||||||
|
ring->alloc_dmabase, ring->alloc_descsize);
|
||||||
if (ring->type == B43_DMA_64BIT)
|
|
||||||
flags |= GFP_DMA;
|
|
||||||
|
|
||||||
ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
|
|
||||||
ring->descbase, ring->dmabase, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the RX DMA channel */
|
/* 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)))
|
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
switch (ring->type) {
|
if (!b43_dma_address_ok(ring, addr, buffersize)) {
|
||||||
case B43_DMA_30BIT:
|
/* We can't support this address. Unmap it again. */
|
||||||
if ((u64)addr + buffersize > (1ULL << 30))
|
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
|
||||||
goto address_error;
|
return 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The address is OK. */
|
/* The address is OK. */
|
||||||
return 0;
|
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)
|
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;
|
meta->dmaaddr = dmaaddr;
|
||||||
ring->ops->fill_descriptor(ring, desc, dmaaddr,
|
ring->ops->fill_descriptor(ring, desc, dmaaddr,
|
||||||
ring->rx_buffersize, 0, 0, 0);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -770,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
|
||||||
for (i = 0; i < ring->nr_slots; i++) {
|
for (i = 0; i < ring->nr_slots; i++) {
|
||||||
desc = ring->ops->idx2desc(ring, i, &meta);
|
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);
|
B43_WARN_ON(!ring->tx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -822,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
||||||
enum b43_dmatype type)
|
enum b43_dmatype type)
|
||||||
{
|
{
|
||||||
struct b43_dmaring *ring;
|
struct b43_dmaring *ring;
|
||||||
int err;
|
int i, err;
|
||||||
dma_addr_t dma_test;
|
dma_addr_t dma_test;
|
||||||
|
|
||||||
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
||||||
|
@ -837,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!ring->meta)
|
if (!ring->meta)
|
||||||
goto err_kfree_ring;
|
goto err_kfree_ring;
|
||||||
|
for (i = 0; i < ring->nr_slots; i++)
|
||||||
|
ring->meta->skb = B43_DMA_PTR_POISON;
|
||||||
|
|
||||||
ring->type = type;
|
ring->type = type;
|
||||||
ring->dev = dev;
|
ring->dev = dev;
|
||||||
|
@ -1147,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
|
||||||
case 0x5000:
|
case 0x5000:
|
||||||
ring = dma->tx_ring_mcast;
|
ring = dma->tx_ring_mcast;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
B43_WARN_ON(1);
|
|
||||||
}
|
}
|
||||||
*slot = (cookie & 0x0FFF);
|
*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;
|
return ring;
|
||||||
}
|
}
|
||||||
|
@ -1246,6 +1354,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
||||||
}
|
}
|
||||||
/* Now transfer the whole frame. */
|
/* Now transfer the whole frame. */
|
||||||
wmb();
|
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));
|
ops->poke_tx(ring, next_slot(ring, slot));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1387,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||||
struct b43_dmaring *ring;
|
struct b43_dmaring *ring;
|
||||||
struct b43_dmadesc_generic *desc;
|
struct b43_dmadesc_generic *desc;
|
||||||
struct b43_dmadesc_meta *meta;
|
struct b43_dmadesc_meta *meta;
|
||||||
int slot;
|
int slot, firstused;
|
||||||
bool frame_succeed;
|
bool frame_succeed;
|
||||||
|
|
||||||
ring = parse_cookie(dev, status->cookie, &slot);
|
ring = parse_cookie(dev, status->cookie, &slot);
|
||||||
if (unlikely(!ring))
|
if (unlikely(!ring))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
B43_WARN_ON(!ring->tx);
|
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;
|
ops = ring->ops;
|
||||||
while (1) {
|
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);
|
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) {
|
if (meta->skb) {
|
||||||
struct b43_private_tx_info *priv_info =
|
struct b43_private_tx_info *priv_info =
|
||||||
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
|
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) {
|
if (meta->is_last_fragment) {
|
||||||
struct ieee80211_tx_info *info;
|
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);
|
info = IEEE80211_SKB_CB(meta->skb);
|
||||||
|
|
||||||
|
@ -1433,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
ieee80211_tx_status(dev->wl->hw, meta->skb);
|
ieee80211_tx_status(dev->wl->hw, meta->skb);
|
||||||
|
|
||||||
/* skb is freed by ieee80211_tx_status() */
|
/* skb will be freed by ieee80211_tx_status().
|
||||||
meta->skb = NULL;
|
* Poison our pointer. */
|
||||||
|
meta->skb = B43_DMA_PTR_POISON;
|
||||||
} else {
|
} else {
|
||||||
/* No need to call free_descriptor_buffer here, as
|
/* No need to call free_descriptor_buffer here, as
|
||||||
* this is only the txhdr, which is not allocated.
|
* 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. */
|
/* Everything unmapped and free'd. So it's not used anymore. */
|
||||||
ring->used_slots--;
|
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;
|
break;
|
||||||
|
}
|
||||||
slot = next_slot(ring, slot);
|
slot = next_slot(ring, slot);
|
||||||
}
|
}
|
||||||
if (ring->stopped) {
|
if (ring->stopped) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef B43_DMA_H_
|
#ifndef B43_DMA_H_
|
||||||
#define B43_DMA_H_
|
#define B43_DMA_H_
|
||||||
|
|
||||||
#include <linux/ieee80211.h>
|
#include <linux/err.h>
|
||||||
|
|
||||||
#include "b43.h"
|
#include "b43.h"
|
||||||
|
|
||||||
|
@ -157,7 +157,6 @@ struct b43_dmadesc_generic {
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
/* Misc DMA constants */
|
/* Misc DMA constants */
|
||||||
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
|
|
||||||
#define B43_DMA0_RX_FRAMEOFFSET 30
|
#define B43_DMA0_RX_FRAMEOFFSET 30
|
||||||
|
|
||||||
/* DMA engine tuning knobs */
|
/* DMA engine tuning knobs */
|
||||||
|
@ -165,6 +164,10 @@ struct b43_dmadesc_generic {
|
||||||
#define B43_RXRING_SLOTS 64
|
#define B43_RXRING_SLOTS 64
|
||||||
#define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN
|
#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 sk_buff;
|
||||||
struct b43_private;
|
struct b43_private;
|
||||||
|
@ -243,6 +246,12 @@ struct b43_dmaring {
|
||||||
/* The QOS priority assigned to this ring. Only used for TX rings.
|
/* The QOS priority assigned to this ring. Only used for TX rings.
|
||||||
* This is the mac80211 "queue" value. */
|
* This is the mac80211 "queue" value. */
|
||||||
u8 queue_prio;
|
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;
|
struct b43_wldev *dev;
|
||||||
#ifdef CONFIG_B43_DEBUG
|
#ifdef CONFIG_B43_DEBUG
|
||||||
/* Maximum number of used slots. */
|
/* Maximum number of used slots. */
|
||||||
|
|
|
@ -296,6 +296,33 @@ static const char *command_types[] = {
|
||||||
};
|
};
|
||||||
#endif
|
#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 */
|
/* 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_commands(struct ipw2100_priv *priv);
|
||||||
static void ipw2100_tx_send_data(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;
|
int i;
|
||||||
|
|
||||||
if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
|
if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
|
||||||
|
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||||
priv->status &= ~STATUS_RF_KILL_HW;
|
priv->status &= ~STATUS_RF_KILL_HW;
|
||||||
return 0;
|
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);
|
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;
|
priv->status |= STATUS_RF_KILL_HW;
|
||||||
else
|
} else {
|
||||||
|
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||||
priv->status &= ~STATUS_RF_KILL_HW;
|
priv->status &= ~STATUS_RF_KILL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
return (value == 0);
|
return (value == 0);
|
||||||
}
|
}
|
||||||
|
@ -1814,13 +1845,6 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
|
||||||
return rc;
|
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)
|
static void ipw2100_down(struct ipw2100_priv *priv)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -1875,6 +1899,64 @@ static void ipw2100_down(struct ipw2100_priv *priv)
|
||||||
netif_stop_queue(priv->net_dev);
|
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)
|
static void ipw2100_reset_adapter(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ipw2100_priv *priv =
|
struct ipw2100_priv *priv =
|
||||||
|
@ -2090,6 +2172,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
|
||||||
priv->net_dev->name);
|
priv->net_dev->name);
|
||||||
|
|
||||||
/* RF_KILL is now enabled (else we wouldn't be here) */
|
/* 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;
|
priv->status |= STATUS_RF_KILL_HW;
|
||||||
|
|
||||||
/* Make sure the RF Kill check timer is running */
|
/* 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 ipw2100_priv *priv;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
|
||||||
dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
|
dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
priv = libipw_priv(dev);
|
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,
|
sysfs_remove_group(&pci_dev->dev.kobj,
|
||||||
&ipw2100_attribute_group);
|
&ipw2100_attribute_group);
|
||||||
|
|
||||||
free_ieee80211(dev);
|
free_ieee80211(dev, 0);
|
||||||
pci_set_drvdata(pci_dev, NULL);
|
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)
|
if (dev->base_addr)
|
||||||
iounmap((void __iomem *)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);
|
pci_release_regions(pci_dev);
|
||||||
|
@ -6601,26 +6687,6 @@ static void __exit ipw2100_exit(void)
|
||||||
module_init(ipw2100_init);
|
module_init(ipw2100_init);
|
||||||
module_exit(ipw2100_exit);
|
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,
|
static int ipw2100_wx_get_name(struct net_device *dev,
|
||||||
struct iw_request_info *info,
|
struct iw_request_info *info,
|
||||||
union iwreq_data *wrqu, char *extra)
|
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 */
|
static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
|
||||||
#endif
|
#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
|
#ifdef CONFIG_IPW2200_QOS
|
||||||
static int qos_enable = 0;
|
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)
|
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;
|
priv->status |= STATUS_RF_KILL_HW;
|
||||||
else
|
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||||
|
} else {
|
||||||
priv->status &= ~STATUS_RF_KILL_HW;
|
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;
|
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) {
|
if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
|
||||||
IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
|
IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
|
||||||
priv->status |= STATUS_RF_KILL_HW;
|
priv->status |= STATUS_RF_KILL_HW;
|
||||||
|
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||||
wake_up_interruptible(&priv->wait_command_queue);
|
wake_up_interruptible(&priv->wait_command_queue);
|
||||||
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
|
||||||
cancel_delayed_work(&priv->request_scan);
|
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)
|
static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
|
||||||
{
|
{
|
||||||
if (channel == 0) {
|
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 */
|
/* Rebase the WE IOCTLs to zero for the handler array */
|
||||||
#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
|
#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
|
||||||
static iw_handler ipw_wx_handlers[] = {
|
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(SIOCSIWFREQ) = ipw_wx_set_freq,
|
||||||
IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
|
IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
|
||||||
IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
|
IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
|
||||||
|
@ -11422,16 +11427,100 @@ static void ipw_bg_down(struct work_struct *work)
|
||||||
/* Called by register_netdev() */
|
/* Called by register_netdev() */
|
||||||
static int ipw_net_init(struct net_device *dev)
|
static int ipw_net_init(struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
int i, rc = 0;
|
||||||
struct ipw_priv *priv = libipw_priv(dev);
|
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);
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
if (ipw_up(priv)) {
|
if (ipw_up(priv)) {
|
||||||
mutex_unlock(&priv->mutex);
|
rc = -EIO;
|
||||||
return -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);
|
mutex_unlock(&priv->mutex);
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCI driver stuff */
|
/* PCI driver stuff */
|
||||||
|
@ -11562,7 +11651,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
|
||||||
if (priv->prom_net_dev)
|
if (priv->prom_net_dev)
|
||||||
return -EPERM;
|
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)
|
if (priv->prom_net_dev == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -11581,7 +11670,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
|
||||||
|
|
||||||
rc = register_netdev(priv->prom_net_dev);
|
rc = register_netdev(priv->prom_net_dev);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
free_ieee80211(priv->prom_net_dev);
|
free_ieee80211(priv->prom_net_dev, 1);
|
||||||
priv->prom_net_dev = NULL;
|
priv->prom_net_dev = NULL;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -11595,7 +11684,7 @@ static void ipw_prom_free(struct ipw_priv *priv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unregister_netdev(priv->prom_net_dev);
|
unregister_netdev(priv->prom_net_dev);
|
||||||
free_ieee80211(priv->prom_net_dev);
|
free_ieee80211(priv->prom_net_dev, 1);
|
||||||
|
|
||||||
priv->prom_net_dev = NULL;
|
priv->prom_net_dev = NULL;
|
||||||
}
|
}
|
||||||
|
@ -11623,7 +11712,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
|
||||||
struct ipw_priv *priv;
|
struct ipw_priv *priv;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
|
net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0);
|
||||||
if (net_dev == NULL) {
|
if (net_dev == NULL) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -11771,7 +11860,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
pci_set_drvdata(pdev, NULL);
|
pci_set_drvdata(pdev, NULL);
|
||||||
out_free_ieee80211:
|
out_free_ieee80211:
|
||||||
free_ieee80211(priv->net_dev);
|
free_ieee80211(priv->net_dev, 0);
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -11838,7 +11927,11 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
pci_set_drvdata(pdev, NULL);
|
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();
|
free_firmware();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/ieee80211.h>
|
#include <linux/ieee80211.h>
|
||||||
|
|
||||||
#include <net/lib80211.h>
|
#include <net/lib80211.h>
|
||||||
|
#include <net/cfg80211.h>
|
||||||
|
|
||||||
#define LIBIPW_VERSION "git-1.1.13"
|
#define LIBIPW_VERSION "git-1.1.13"
|
||||||
|
|
||||||
|
@ -783,12 +784,15 @@ struct libipw_geo {
|
||||||
|
|
||||||
struct libipw_device {
|
struct libipw_device {
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
struct wireless_dev wdev;
|
||||||
struct libipw_security sec;
|
struct libipw_security sec;
|
||||||
|
|
||||||
/* Bookkeeping structures */
|
/* Bookkeeping structures */
|
||||||
struct libipw_stats ieee_stats;
|
struct libipw_stats ieee_stats;
|
||||||
|
|
||||||
struct libipw_geo geo;
|
struct libipw_geo geo;
|
||||||
|
struct ieee80211_supported_band bg_band;
|
||||||
|
struct ieee80211_supported_band a_band;
|
||||||
|
|
||||||
/* Probe / Beacon management */
|
/* Probe / Beacon management */
|
||||||
struct list_head network_free_list;
|
struct list_head network_free_list;
|
||||||
|
@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ieee80211.c */
|
/* ieee80211.c */
|
||||||
extern void free_ieee80211(struct net_device *dev);
|
extern void free_ieee80211(struct net_device *dev, int monitor);
|
||||||
extern struct net_device *alloc_ieee80211(int sizeof_priv);
|
extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
|
||||||
extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
|
extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
|
||||||
|
|
||||||
extern void libipw_networks_age(struct libipw_device *ieee,
|
extern void libipw_networks_age(struct libipw_device *ieee,
|
||||||
|
|
|
@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
||||||
MODULE_AUTHOR(DRV_COPYRIGHT);
|
MODULE_AUTHOR(DRV_COPYRIGHT);
|
||||||
MODULE_LICENSE("GPL");
|
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)
|
static int libipw_networks_allocate(struct libipw_device *ieee)
|
||||||
{
|
{
|
||||||
if (ieee->networks)
|
if (ieee->networks)
|
||||||
|
@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(libipw_change_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 libipw_device *ieee;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
|
||||||
|
|
||||||
ieee->dev = dev;
|
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);
|
err = libipw_networks_allocate(ieee);
|
||||||
if (err) {
|
if (err) {
|
||||||
LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
|
LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
|
||||||
goto failed_free_netdev;
|
goto failed_free_wiphy;
|
||||||
}
|
}
|
||||||
libipw_networks_initialize(ieee);
|
libipw_networks_initialize(ieee);
|
||||||
|
|
||||||
|
@ -193,19 +217,27 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
|
|
||||||
|
failed_free_wiphy:
|
||||||
|
if (!monitor)
|
||||||
|
wiphy_free(ieee->wdev.wiphy);
|
||||||
failed_free_netdev:
|
failed_free_netdev:
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
failed:
|
failed:
|
||||||
return NULL;
|
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);
|
struct libipw_device *ieee = netdev_priv(dev);
|
||||||
|
|
||||||
lib80211_crypt_info_free(&ieee->crypt_info);
|
lib80211_crypt_info_free(&ieee->crypt_info);
|
||||||
|
|
||||||
libipw_networks_free(ieee);
|
libipw_networks_free(ieee);
|
||||||
|
|
||||||
|
/* free cfg80211 resources */
|
||||||
|
if (!monitor)
|
||||||
|
wiphy_free(ieee->wdev.wiphy);
|
||||||
|
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
|
||||||
.use_rts_for_ht = true, /* use rts/cts protection */
|
.use_rts_for_ht = true, /* use rts/cts protection */
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||||
.support_ct_kill_exit = true,
|
.support_ct_kill_exit = true,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl1000_bg_cfg = {
|
struct iwl_cfg iwl1000_bg_cfg = {
|
||||||
|
|
|
@ -221,22 +221,13 @@ struct iwl3945_ibss_seq {
|
||||||
* for use by iwl-*.c
|
* 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_db_from_ratio(int sig_ratio);
|
||||||
extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
|
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_replenish(void *data);
|
||||||
extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
|
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,
|
extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
|
||||||
struct ieee80211_hdr *hdr,int left);
|
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);
|
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->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
|
||||||
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
|
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
|
||||||
addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
|
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->reserved1 = cpu_to_le16(0);
|
||||||
addsta->reserved2 = cpu_to_le32(0);
|
addsta->reserved2 = cpu_to_le16(0);
|
||||||
|
|
||||||
return (u16)sizeof(struct iwl4965_addsta_cmd);
|
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 = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
||||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||||
info->flags |= iwl_is_tx_success(status) ?
|
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||||
IEEE80211_TX_STAT_ACK : 0;
|
|
||||||
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
||||||
/* FIXME: code repetition end */
|
/* FIXME: code repetition end */
|
||||||
|
|
||||||
|
@ -2021,8 +2021,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||||
info->flags |= iwl_is_tx_success(status) ?
|
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||||
IEEE80211_TX_STAT_ACK : 0;
|
|
||||||
iwl_hwrate_to_tx_control(priv,
|
iwl_hwrate_to_tx_control(priv,
|
||||||
le32_to_cpu(tx_resp->rate_n_flags),
|
le32_to_cpu(tx_resp->rate_n_flags),
|
||||||
info);
|
info);
|
||||||
|
@ -2240,6 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
|
||||||
.broken_powersave = true,
|
.broken_powersave = true,
|
||||||
.led_compensation = 61,
|
.led_compensation = 61,
|
||||||
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Module firmware */
|
/* 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 = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
||||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||||
info->flags |= iwl_is_tx_success(status) ?
|
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||||
IEEE80211_TX_STAT_ACK : 0;
|
|
||||||
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
|
||||||
|
|
||||||
/* FIXME: code repetition end */
|
/* 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);
|
BUG_ON(txq_id != txq->swq_id);
|
||||||
|
|
||||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||||
info->flags |= iwl_is_tx_success(status) ?
|
info->flags |= iwl_tx_status_to_mac80211(status);
|
||||||
IEEE80211_TX_STAT_ACK : 0;
|
|
||||||
iwl_hwrate_to_tx_control(priv,
|
iwl_hwrate_to_tx_control(priv,
|
||||||
le32_to_cpu(tx_resp->rate_n_flags),
|
le32_to_cpu(tx_resp->rate_n_flags),
|
||||||
info);
|
info);
|
||||||
|
@ -1251,6 +1249,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv)
|
||||||
|
|
||||||
/* half dBm need to multiply */
|
/* half dBm need to multiply */
|
||||||
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
|
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.flags = IWL50_TX_POWER_NO_CLOSED;
|
||||||
tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
|
tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
|
||||||
|
|
||||||
|
@ -1584,14 +1598,15 @@ struct iwl_cfg iwl5300_agn_cfg = {
|
||||||
.ht_greenfield_support = true,
|
.ht_greenfield_support = true,
|
||||||
.led_compensation = 51,
|
.led_compensation = 51,
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl5100_bg_cfg = {
|
struct iwl_cfg iwl5100_bgn_cfg = {
|
||||||
.name = "5100BG",
|
.name = "5100BGN",
|
||||||
.fw_name_pre = IWL5000_FW_PRE,
|
.fw_name_pre = IWL5000_FW_PRE,
|
||||||
.ucode_api_max = IWL5000_UCODE_API_MAX,
|
.ucode_api_max = IWL5000_UCODE_API_MAX,
|
||||||
.ucode_api_min = IWL5000_UCODE_API_MIN,
|
.ucode_api_min = IWL5000_UCODE_API_MIN,
|
||||||
.sku = IWL_SKU_G,
|
.sku = IWL_SKU_G|IWL_SKU_N,
|
||||||
.ops = &iwl5000_ops,
|
.ops = &iwl5000_ops,
|
||||||
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
||||||
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
||||||
|
@ -1627,7 +1642,6 @@ struct iwl_cfg iwl5100_abg_cfg = {
|
||||||
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
|
||||||
.set_l0s = true,
|
.set_l0s = true,
|
||||||
.use_bsm = false,
|
.use_bsm = false,
|
||||||
.ht_greenfield_support = true,
|
|
||||||
.led_compensation = 51,
|
.led_compensation = 51,
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||||
};
|
};
|
||||||
|
@ -1653,6 +1667,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
|
||||||
.ht_greenfield_support = true,
|
.ht_greenfield_support = true,
|
||||||
.led_compensation = 51,
|
.led_compensation = 51,
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl5350_agn_cfg = {
|
struct iwl_cfg iwl5350_agn_cfg = {
|
||||||
|
@ -1676,6 +1691,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
|
||||||
.ht_greenfield_support = true,
|
.ht_greenfield_support = true,
|
||||||
.led_compensation = 51,
|
.led_compensation = 51,
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl5150_agn_cfg = {
|
struct iwl_cfg iwl5150_agn_cfg = {
|
||||||
|
@ -1699,6 +1715,29 @@ struct iwl_cfg iwl5150_agn_cfg = {
|
||||||
.ht_greenfield_support = true,
|
.ht_greenfield_support = true,
|
||||||
.led_compensation = 51,
|
.led_compensation = 51,
|
||||||
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
|
.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));
|
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
|
||||||
|
|
|
@ -306,6 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
|
||||||
.supports_idle = true,
|
.supports_idle = true,
|
||||||
.adv_thermal_throttle = true,
|
.adv_thermal_throttle = true,
|
||||||
.support_ct_kill_exit = true,
|
.support_ct_kill_exit = true,
|
||||||
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl6000i_2abg_cfg = {
|
struct iwl_cfg iwl6000i_2abg_cfg = {
|
||||||
|
@ -394,8 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
|
||||||
.supports_idle = true,
|
.supports_idle = true,
|
||||||
.adv_thermal_throttle = true,
|
.adv_thermal_throttle = true,
|
||||||
.support_ct_kill_exit = true,
|
.support_ct_kill_exit = true,
|
||||||
.support_sm_ps = true,
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
|
||||||
.support_wimax_coexist = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl6050_2abg_cfg = {
|
struct iwl_cfg iwl6050_2abg_cfg = {
|
||||||
|
@ -425,7 +425,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
|
||||||
.supports_idle = true,
|
.supports_idle = true,
|
||||||
.adv_thermal_throttle = true,
|
.adv_thermal_throttle = true,
|
||||||
.support_ct_kill_exit = true,
|
.support_ct_kill_exit = true,
|
||||||
.support_wimax_coexist = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl6000_3agn_cfg = {
|
struct iwl_cfg iwl6000_3agn_cfg = {
|
||||||
|
@ -456,38 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
|
||||||
.supports_idle = true,
|
.supports_idle = true,
|
||||||
.adv_thermal_throttle = true,
|
.adv_thermal_throttle = true,
|
||||||
.support_ct_kill_exit = true,
|
.support_ct_kill_exit = true,
|
||||||
};
|
.sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
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) {
|
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
|
||||||
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
|
IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
|
||||||
sta->addr, tid);
|
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;
|
struct iwl_lq_sta *lq_sta = priv_sta;
|
||||||
lq_sta->rs_sta_dbgfs_scale_table_file =
|
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_scale_table_ops);
|
||||||
lq_sta->rs_sta_dbgfs_stats_table_file =
|
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_stats_table_ops);
|
||||||
lq_sta->rs_sta_dbgfs_rate_scale_data_file =
|
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_rate_scale_data_ops);
|
||||||
lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
|
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);
|
&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);
|
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,
|
struct ieee80211_hdr *hdr,
|
||||||
int left)
|
int left)
|
||||||
{
|
{
|
||||||
|
@ -328,34 +328,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
|
||||||
return priv->ibss_beacon->len;
|
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,
|
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;
|
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;
|
tx_beacon_cmd = &frame->u.beacon;
|
||||||
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
|
memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
|
||||||
|
|
||||||
tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
|
/* Set up TX beacon contents */
|
||||||
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
|
||||||
|
|
||||||
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
|
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
|
||||||
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
|
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);
|
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
|
||||||
|
tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
|
||||||
if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
|
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
||||||
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.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
|
tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
|
||||||
TX_CMD_FLG_TSF_MSK |
|
TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_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;
|
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;
|
struct iwl_frame *frame;
|
||||||
unsigned int frame_size;
|
unsigned int frame_size;
|
||||||
int rc;
|
int rc;
|
||||||
u8 rate;
|
|
||||||
|
|
||||||
frame = iwl_get_free_frame(priv);
|
frame = iwl_get_free_frame(priv);
|
||||||
|
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
|
IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
|
||||||
"command.\n");
|
"command.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
rate = iwl_rate_get_lowest_plcp(priv);
|
frame_size = iwl_hw_get_beacon_cmd(priv, frame);
|
||||||
|
if (!frame_size) {
|
||||||
frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
|
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,
|
rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
|
||||||
&frame->u.cmd[0]);
|
&frame->u.cmd[0]);
|
||||||
|
@ -613,7 +654,7 @@ static void iwl_bg_statistics_periodic(unsigned long data)
|
||||||
if (!iwl_is_ready_rf(priv))
|
if (!iwl_is_ready_rf(priv))
|
||||||
return;
|
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,
|
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 request from the host as well as for the periodic
|
||||||
* statistics notifications (after received beacons) from the uCode.
|
* 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;
|
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
|
||||||
|
|
||||||
iwl_setup_spectrum_handlers(priv);
|
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)) {
|
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
|
||||||
iwl_rx_handle(priv);
|
iwl_rx_handle(priv);
|
||||||
priv->isr_stats.rx++;
|
priv->isr_stats.rx++;
|
||||||
iwl_leds_background(priv);
|
|
||||||
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
|
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.
|
* 3- update RX shared data to indicate last write index.
|
||||||
* 4- send interrupt.
|
* 4- send interrupt.
|
||||||
* This could lead to RX race, driver could receive RX interrupt
|
* This could lead to RX race, driver could receive RX interrupt
|
||||||
* but the shared data changes does not reflect this.
|
* but the shared data changes does not reflect this;
|
||||||
* this could lead to RX race, RX periodic will solve this race
|
* 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);
|
CSR_INT_PERIODIC_DIS);
|
||||||
iwl_rx_handle(priv);
|
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))
|
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);
|
CSR_INT_PERIODIC_ENA);
|
||||||
|
|
||||||
priv->isr_stats.rx++;
|
priv->isr_stats.rx++;
|
||||||
iwl_leds_background(priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This "Tx" DMA channel is used only for loading uCode */
|
/* 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
static const char *desc_lookup_text[] = {
|
static const char *desc_lookup_text[] = {
|
||||||
"OK",
|
"OK",
|
||||||
"FAIL",
|
"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);
|
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 */
|
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||||
#define MAX_EVENT_LOG_SIZE (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 base; /* SRAM byte address of event log header */
|
||||||
u32 capacity; /* event log capacity in # entries */
|
u32 capacity; /* event log capacity in # entries */
|
||||||
|
@ -1758,19 +1837,37 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
size, num_wraps);
|
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);
|
||||||
|
|
||||||
/* if uCode has wrapped back to top of log, start at the oldest entry,
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
* i.e the next one that uCode would fill. */
|
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)
|
if (num_wraps)
|
||||||
iwl_print_event_log(priv, next_entry,
|
iwl_print_event_log(priv, next_entry,
|
||||||
capacity - next_entry, mode);
|
capacity - next_entry, mode);
|
||||||
/* (then/else) start at top of log */
|
/* (then/else) start at top of log */
|
||||||
iwl_print_event_log(priv, 0, next_entry, mode);
|
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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_alive_start - called after REPLY_ALIVE notification received
|
* 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_STATION) |
|
||||||
BIT(NL80211_IFTYPE_ADHOC);
|
BIT(NL80211_IFTYPE_ADHOC);
|
||||||
|
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
|
||||||
|
WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||||
/* Firmware does not support this */
|
|
||||||
hw->wiphy->disable_beacon_hints = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For now, disable PS by default because it affects
|
* For now, disable PS by default because it affects
|
||||||
* RX performance significantly.
|
* 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;
|
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
|
||||||
/* we create the 802.11 header and a zero-length SSID element */
|
/* 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 - "
|
IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
|
||||||
"Attempting to continue.\n");
|
"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)
|
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
||||||
priv->cfg->ops->hcmd->set_rxon_chain(priv);
|
priv->cfg->ops->hcmd->set_rxon_chain(priv);
|
||||||
|
|
||||||
|
@ -2551,6 +2650,7 @@ void iwl_config_ap(struct iwl_priv *priv)
|
||||||
/* restore RXON assoc */
|
/* restore RXON assoc */
|
||||||
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
iwl_reset_qos(priv);
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
iwl_activate_qos(priv, 1);
|
iwl_activate_qos(priv, 1);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
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,
|
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||||
{
|
{
|
||||||
|
@ -2699,6 +2800,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
|
||||||
return 0;
|
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
|
* sysfs attributes
|
||||||
|
@ -2893,7 +3033,7 @@ static ssize_t show_statistics(struct device *d,
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
rc = iwl_send_statistics_request(priv, 0);
|
rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -3045,10 +3185,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
|
||||||
priv->band = IEEE80211_BAND_2GHZ;
|
priv->band = IEEE80211_BAND_2GHZ;
|
||||||
|
|
||||||
priv->iw_mode = NL80211_IFTYPE_STATION;
|
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 */
|
/* Choose which receivers/antennas to use */
|
||||||
if (priv->cfg->ops->hcmd->set_rxon_chain)
|
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,
|
.reset_tsf = iwl_mac_reset_tsf,
|
||||||
.bss_info_changed = iwl_bss_info_changed,
|
.bss_info_changed = iwl_bss_info_changed,
|
||||||
.ampdu_action = iwl_mac_ampdu_action,
|
.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)
|
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)},
|
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
|
||||||
#endif /* CONFIG_IWL4965 */
|
#endif /* CONFIG_IWL4965 */
|
||||||
#ifdef CONFIG_IWL5000
|
#ifdef CONFIG_IWL5000
|
||||||
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
|
/* 5100 Series WiFi */
|
||||||
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
|
||||||
/* 5350 WiFi/WiMax */
|
{IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
|
||||||
/* 5150 Wifi/WiMax */
|
{IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
|
{IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
|
||||||
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
|
{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 */
|
/* 6x00 Series */
|
||||||
{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
|
{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)},
|
{IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
|
||||||
|
|
||||||
/* 6x50 WiFi/WiMax Series */
|
/* 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, 0x1301, iwl6050_2agn_cfg)},
|
||||||
{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
|
{IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
|
||||||
{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
|
{IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
|
||||||
{IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_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, 0x1311, iwl6050_2agn_cfg)},
|
||||||
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_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
|
/* Ask for statistics now, the uCode will send notification
|
||||||
* periodically after association */
|
* 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);
|
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_TX_RATE_MSK 0x04
|
||||||
#define STA_MODIFY_ADDBA_TID_MSK 0x08
|
#define STA_MODIFY_ADDBA_TID_MSK 0x08
|
||||||
#define STA_MODIFY_DELBA_TID_MSK 0x10
|
#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),
|
/* Receiver address (actually, Rx station's index into station table),
|
||||||
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
|
* 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. */
|
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
||||||
__le16 add_immediate_ba_ssn;
|
__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));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* 5000 */
|
/* 5000 */
|
||||||
|
@ -1138,7 +1146,14 @@ struct iwl_addsta_cmd {
|
||||||
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
||||||
__le16 add_immediate_ba_ssn;
|
__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));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
@ -1690,6 +1705,21 @@ enum {
|
||||||
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
|
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)
|
static inline bool iwl_is_tx_success(u32 status)
|
||||||
{
|
{
|
||||||
status &= TX_STATUS_MSK;
|
status &= TX_STATUS_MSK;
|
||||||
|
@ -3071,6 +3101,10 @@ struct statistics_general {
|
||||||
__le32 reserved3;
|
__le32 reserved3;
|
||||||
} __attribute__ ((packed));
|
} __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,
|
* REPLY_STATISTICS_CMD = 0x9c,
|
||||||
* 3945 and 4965 identical.
|
* 3945 and 4965 identical.
|
||||||
|
|
|
@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
|
||||||
}
|
}
|
||||||
return ant;
|
return ant;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(iwl_toggle_tx_ant);
|
||||||
|
|
||||||
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
EXPORT_SYMBOL(iwl_bcast_addr);
|
EXPORT_SYMBOL(iwl_bcast_addr);
|
||||||
|
@ -255,7 +256,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
|
||||||
/* nic_init */
|
/* nic_init */
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
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);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
|
|
||||||
ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
|
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)
|
if (priv->cfg->ht_greenfield_support)
|
||||||
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
|
||||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||||
if (priv->cfg->support_sm_ps)
|
|
||||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
||||||
(WLAN_HT_CAP_SM_PS_DYNAMIC << 2));
|
(priv->cfg->sm_ps_mode << 2));
|
||||||
else
|
|
||||||
ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
|
|
||||||
(WLAN_HT_CAP_SM_PS_DISABLED << 2));
|
|
||||||
|
|
||||||
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
max_bit_rate = MAX_BIT_RATE_20_MHZ;
|
||||||
if (priv->hw_params.ht40_channel & BIT(band)) {
|
if (priv->hw_params.ht40_channel & BIT(band)) {
|
||||||
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||||
|
@ -1007,26 +1006,24 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
|
||||||
int idle_cnt = active_cnt;
|
int idle_cnt = active_cnt;
|
||||||
bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
|
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 */
|
/* # Rx chains when idling and maybe trying to save power */
|
||||||
switch (priv->current_ht_config.sm_ps) {
|
switch (priv->cfg->sm_ps_mode) {
|
||||||
case WLAN_HT_CAP_SM_PS_STATIC:
|
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:
|
case WLAN_HT_CAP_SM_PS_DYNAMIC:
|
||||||
idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
|
idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
|
||||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
IWL_NUM_IDLE_CHAINS_SINGLE;
|
||||||
break;
|
break;
|
||||||
case WLAN_HT_CAP_SM_PS_DISABLED:
|
case WLAN_HT_CAP_SM_PS_DISABLED:
|
||||||
idle_cnt = (is_cam) ? active_cnt :
|
|
||||||
IWL_NUM_IDLE_CHAINS_SINGLE;
|
|
||||||
break;
|
break;
|
||||||
case WLAN_HT_CAP_SM_PS_INVALID:
|
case WLAN_HT_CAP_SM_PS_INVALID:
|
||||||
default:
|
default:
|
||||||
IWL_ERR(priv, "invalid sm_ps mode %d\n",
|
IWL_ERR(priv, "invalid sm_ps mode %u\n",
|
||||||
priv->current_ht_config.sm_ps);
|
priv->cfg->sm_ps_mode);
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return idle_cnt;
|
return idle_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1365,12 +1362,11 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
|
||||||
/* Cancel currently queued command. */
|
/* Cancel currently queued command. */
|
||||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
|
||||||
|
|
||||||
#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_error_log(priv);
|
||||||
priv->cfg->ops->lib->dump_nic_event_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)
|
||||||
iwl_print_rx_config_cmd(priv);
|
iwl_print_rx_config_cmd(priv);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wake_up_interruptible(&priv->wait_command_queue);
|
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);
|
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_statistics_cmd statistics_cmd = {
|
||||||
struct iwl_host_cmd cmd = {
|
.configuration_flags =
|
||||||
.id = REPLY_STATISTICS_CMD,
|
clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
|
||||||
.flags = flags,
|
|
||||||
.len = sizeof(stat_flags),
|
|
||||||
.data = (u8 *) &stat_flags,
|
|
||||||
};
|
};
|
||||||
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);
|
EXPORT_SYMBOL(iwl_send_statistics_request);
|
||||||
|
|
||||||
|
@ -2477,6 +2478,16 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
} else {
|
} else {
|
||||||
priv->assoc_id = 0;
|
priv->assoc_id = 0;
|
||||||
iwl_led_disassociate(priv);
|
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);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
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));
|
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));
|
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_cnt++;
|
||||||
stats->data_bytes += len;
|
stats->data_bytes += len;
|
||||||
}
|
}
|
||||||
|
iwl_leds_background(priv);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_update_stats);
|
EXPORT_SYMBOL(iwl_update_stats);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -167,7 +167,7 @@ struct iwl_lib_ops {
|
||||||
int (*is_valid_rtc_data_addr)(u32 addr);
|
int (*is_valid_rtc_data_addr)(u32 addr);
|
||||||
/* 1st ucode load */
|
/* 1st ucode load */
|
||||||
int (*load_ucode)(struct iwl_priv *priv);
|
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);
|
void (*dump_nic_error_log)(struct iwl_priv *priv);
|
||||||
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
|
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
|
||||||
/* power management */
|
/* power management */
|
||||||
|
@ -228,7 +228,7 @@ struct iwl_mod_params {
|
||||||
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
* @chain_noise_num_beacons: number of beacons used to compute chain noise
|
||||||
* @adv_thermal_throttle: support advance thermal throttle
|
* @adv_thermal_throttle: support advance thermal throttle
|
||||||
* @support_ct_kill_exit: support ct kill exit condition
|
* @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
|
* @support_wimax_coexist: support wimax/wifi co-exist
|
||||||
*
|
*
|
||||||
* We enable the driver to be backward compatible wrt API version. The
|
* We enable the driver to be backward compatible wrt API version. The
|
||||||
|
@ -285,7 +285,7 @@ struct iwl_cfg {
|
||||||
const bool supports_idle;
|
const bool supports_idle;
|
||||||
bool adv_thermal_throttle;
|
bool adv_thermal_throttle;
|
||||||
bool support_ct_kill_exit;
|
bool support_ct_kill_exit;
|
||||||
bool support_sm_ps;
|
u8 sm_ps_mode;
|
||||||
const bool support_wimax_coexist;
|
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);
|
u16 length, struct ieee80211_hdr *header);
|
||||||
const char *get_mgmt_string(int cmd);
|
const char *get_mgmt_string(int cmd);
|
||||||
const char *get_ctrl_string(int cmd);
|
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);
|
||||||
void iwl_clear_rx_stats(struct iwl_priv *priv);
|
|
||||||
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
|
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc,
|
||||||
u16 len);
|
u16 len);
|
||||||
#else
|
#else
|
||||||
|
@ -390,6 +389,7 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
|
||||||
/* data */
|
/* data */
|
||||||
stats->data_bytes += len;
|
stats->data_bytes += len;
|
||||||
}
|
}
|
||||||
|
iwl_leds_background(priv);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
|
@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
|
||||||
struct iwl_rx_mem_buffer *rxb);
|
struct iwl_rx_mem_buffer *rxb);
|
||||||
void iwl_rx_statistics(struct iwl_priv *priv,
|
void iwl_rx_statistics(struct iwl_priv *priv,
|
||||||
struct iwl_rx_mem_buffer *rxb);
|
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);
|
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
|
||||||
|
|
||||||
/* TX helpers */
|
/* TX helpers */
|
||||||
|
@ -576,19 +578,11 @@ int iwl_pci_resume(struct pci_dev *pdev);
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
* Error Handling Debugging
|
* 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_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);
|
void iwl_print_rx_config_cmd(struct iwl_priv *priv);
|
||||||
#else
|
#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)
|
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 void iwl_rf_kill_ct_config(struct iwl_priv *priv);
|
||||||
extern int iwl_send_bt_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_verify_ucode(struct iwl_priv *priv);
|
||||||
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
|
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
|
||||||
struct iwl_link_quality_cmd *lq, u8 flags);
|
struct iwl_link_quality_cmd *lq, u8 flags);
|
||||||
|
|
|
@ -62,7 +62,25 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
#ifndef __iwl_csr_h__
|
#ifndef __iwl_csr_h__
|
||||||
#define __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_BASE (0x000)
|
||||||
|
|
||||||
#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
|
#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
|
||||||
|
@ -74,42 +92,65 @@
|
||||||
#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
|
#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
|
||||||
#define CSR_GP_CNTRL (CSR_BASE+0x024)
|
#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
|
* Hardware revision info
|
||||||
* Bit fields:
|
* Bit fields:
|
||||||
* 31-8: Reserved
|
* 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
|
* 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: 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)
|
#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_REG (CSR_BASE+0x02c)
|
||||||
#define CSR_EEPROM_GP (CSR_BASE+0x030)
|
#define CSR_EEPROM_GP (CSR_BASE+0x030)
|
||||||
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
|
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
|
||||||
|
|
||||||
#define CSR_GIO_REG (CSR_BASE+0x03C)
|
#define CSR_GIO_REG (CSR_BASE+0x03C)
|
||||||
#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
|
#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
|
||||||
#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
|
#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 (CSR_BASE+0x054)
|
||||||
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
|
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
|
||||||
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
|
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
|
||||||
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
|
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
|
||||||
|
|
||||||
#define CSR_LED_REG (CSR_BASE+0x094)
|
#define CSR_LED_REG (CSR_BASE+0x094)
|
||||||
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
|
#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_GIO_CHICKEN_BITS (CSR_BASE+0x100)
|
||||||
|
|
||||||
#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005)
|
|
||||||
/* Analog phase-lock-loop configuration */
|
/* Analog phase-lock-loop configuration */
|
||||||
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
|
#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:
|
* Bit fields:
|
||||||
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
|
* 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_HW_REV_WA_REG (CSR_BASE+0x22C)
|
||||||
|
|
||||||
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
|
#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
|
||||||
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
|
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
|
||||||
|
|
||||||
|
@ -128,12 +169,12 @@
|
||||||
|
|
||||||
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
|
#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_EEPROM_OWN_SEM (0x00200000)
|
||||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000)
|
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
|
||||||
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000)
|
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
|
||||||
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000)
|
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
|
||||||
|
|
||||||
#define CSR_INT_PERIODIC_DIS (0x00)
|
#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/
|
||||||
#define CSR_INT_PERIODIC_ENA (0xFF)
|
#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/
|
||||||
|
|
||||||
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
|
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
|
||||||
* acknowledged (reset) by host writing "1" to flagged bits. */
|
* acknowledged (reset) by host writing "1" to flagged bits. */
|
||||||
|
@ -198,7 +239,44 @@
|
||||||
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
|
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
|
||||||
#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
|
#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_MAC_CLOCK_READY (0x00000001)
|
||||||
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
|
#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
|
||||||
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
|
#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
|
||||||
|
@ -231,28 +309,58 @@
|
||||||
#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)
|
#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)
|
||||||
|
|
||||||
/* EEPROM GP */
|
/* 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_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_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_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_CORR_STATUS_MSK (0x00100000) /* bit 20 */
|
||||||
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
|
#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_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
|
||||||
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
|
#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
|
||||||
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
|
#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
|
||||||
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
|
#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
|
||||||
#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
|
#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 */
|
/* CSR GIO */
|
||||||
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
|
#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_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
|
||||||
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
|
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
|
||||||
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
|
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
|
||||||
|
@ -265,7 +373,7 @@
|
||||||
#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
|
#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_L1A_NO_L0S_RX (0x00800000)
|
||||||
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
|
#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_INT_TBL_ENABLE (1 << 31)
|
||||||
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
|
#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)
|
#define HBUS_BASE (0x400)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
|
* Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
|
||||||
* structures, error log, event log, verifying uCode load).
|
* structures, error log, event log, verifying uCode load).
|
||||||
|
@ -301,6 +424,10 @@
|
||||||
#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
|
#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
|
||||||
#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
|
#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
|
* Registers for accessing device's internal peripheral registers
|
||||||
* (e.g. SCD, BSM, etc.). First write to address register,
|
* (e.g. SCD, BSM, etc.). First write to address register,
|
||||||
|
@ -315,16 +442,12 @@
|
||||||
#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
|
#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).
|
* Indicates index to next TFD that driver will fill (1 past latest filled).
|
||||||
* Bit usage:
|
* Bit usage:
|
||||||
* 0-7: queue write index
|
* 0-7: queue write index
|
||||||
* 11-8: queue selector
|
* 11-8: queue selector
|
||||||
*/
|
*/
|
||||||
#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
|
#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__ */
|
#endif /* !__iwl_csr_h__ */
|
||||||
|
|
|
@ -107,6 +107,8 @@ struct iwl_debugfs {
|
||||||
struct dentry *file_chain_noise;
|
struct dentry *file_chain_noise;
|
||||||
struct dentry *file_tx_power;
|
struct dentry *file_tx_power;
|
||||||
struct dentry *file_power_save_status;
|
struct dentry *file_power_save_status;
|
||||||
|
struct dentry *file_clear_ucode_statistics;
|
||||||
|
struct dentry *file_clear_traffic_statistics;
|
||||||
} dbgfs_debug_files;
|
} dbgfs_debug_files;
|
||||||
u32 sram_offset;
|
u32 sram_offset;
|
||||||
u32 sram_len;
|
u32 sram_len;
|
||||||
|
|
|
@ -47,9 +47,9 @@
|
||||||
goto err; \
|
goto err; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DEBUGFS_ADD_FILE(name, parent) do { \
|
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
|
||||||
dbgfs->dbgfs_##parent##_files.file_##name = \
|
dbgfs->dbgfs_##parent##_files.file_##name = \
|
||||||
debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
|
debugfs_create_file(#name, mode, \
|
||||||
dbgfs->dir_##parent, priv, \
|
dbgfs->dir_##parent, priv, \
|
||||||
&iwl_dbgfs_##name##_ops); \
|
&iwl_dbgfs_##name##_ops); \
|
||||||
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
|
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
|
||||||
|
@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
||||||
|
|
||||||
int cnt;
|
int cnt;
|
||||||
ssize_t ret;
|
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);
|
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
|
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
|
||||||
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"\t%s\t\t: %u\n",
|
"\t%25s\t\t: %u\n",
|
||||||
get_mgmt_string(cnt),
|
get_mgmt_string(cnt),
|
||||||
priv->tx_stats.mgmt[cnt]);
|
priv->tx_stats.mgmt[cnt]);
|
||||||
}
|
}
|
||||||
pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
|
pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
|
||||||
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"\t%s\t\t: %u\n",
|
"\t%25s\t\t: %u\n",
|
||||||
get_ctrl_string(cnt),
|
get_ctrl_string(cnt),
|
||||||
priv->tx_stats.ctrl[cnt]);
|
priv->tx_stats.ctrl[cnt]);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +160,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
|
||||||
return ret;
|
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,
|
const char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
|
@ -174,8 +175,7 @@ static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (sscanf(buf, "%x", &clear_flag) != 1)
|
if (sscanf(buf, "%x", &clear_flag) != 1)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (clear_flag == 1)
|
iwl_clear_traffic_stats(priv);
|
||||||
iwl_clear_tx_stats(priv);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
||||||
int cnt;
|
int cnt;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
const size_t bufsz = 100 +
|
const size_t bufsz = 100 +
|
||||||
sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX);
|
sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
|
||||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
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");
|
pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
|
||||||
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"\t%s\t\t: %u\n",
|
"\t%25s\t\t: %u\n",
|
||||||
get_mgmt_string(cnt),
|
get_mgmt_string(cnt),
|
||||||
priv->rx_stats.mgmt[cnt]);
|
priv->rx_stats.mgmt[cnt]);
|
||||||
}
|
}
|
||||||
pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
|
pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
|
||||||
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"\t%s\t\t: %u\n",
|
"\t%25s\t\t: %u\n",
|
||||||
get_ctrl_string(cnt),
|
get_ctrl_string(cnt),
|
||||||
priv->rx_stats.ctrl[cnt]);
|
priv->rx_stats.ctrl[cnt]);
|
||||||
}
|
}
|
||||||
|
@ -220,26 +220,6 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
|
||||||
return ret;
|
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 BYTE1_MASK 0x000000ff;
|
||||||
#define BYTE2_MASK 0x0000ffff;
|
#define BYTE2_MASK 0x0000ffff;
|
||||||
#define BYTE3_MASK 0x00ffffff;
|
#define BYTE3_MASK 0x00ffffff;
|
||||||
|
@ -248,13 +228,29 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
char buf[1024];
|
char *buf;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
int i;
|
int i;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
|
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) {
|
for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
|
||||||
val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
|
val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
|
||||||
priv->dbgfs->sram_len - i);
|
priv->dbgfs->sram_len - i);
|
||||||
|
@ -271,11 +267,14 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||||
break;
|
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, "0x%08x ", val);
|
||||||
}
|
}
|
||||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||||
|
|
||||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||||
|
kfree(buf);
|
||||||
return ret;
|
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,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"flags: 0x%x\n",
|
"flags: 0x%x\n",
|
||||||
station->sta.station_flags_msk);
|
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, "tid data:\n");
|
||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"seq_num\t\ttxq_id");
|
"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)
|
if (sscanf(buf, "%d", &event_log_flag) != 1)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (event_log_flag == 1)
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -986,7 +983,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int cnt;
|
int cnt;
|
||||||
int ret;
|
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) {
|
if (!priv->txq) {
|
||||||
IWL_ERR(priv, "txq not ready\n");
|
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);
|
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,
|
static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
|
||||||
int bufsz)
|
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 */
|
/* make request to uCode to retrieve statistics information */
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
ret = iwl_send_statistics_request(priv, 0);
|
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (ret) {
|
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 */
|
/* make request to uCode to retrieve statistics information */
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
ret = iwl_send_statistics_request(priv, 0);
|
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (ret) {
|
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 */
|
/* make request to uCode to retrieve statistics information */
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
ret = iwl_send_statistics_request(priv, 0);
|
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1770,7 +1763,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
|
||||||
else {
|
else {
|
||||||
/* make request to uCode to retrieve statistics information */
|
/* make request to uCode to retrieve statistics information */
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
ret = iwl_send_statistics_request(priv, 0);
|
ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (ret) {
|
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);
|
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
|
static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
|
||||||
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
|
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_WRITE_FILE_OPS(traffic_log);
|
||||||
DEBUGFS_READ_FILE_OPS(rx_queue);
|
DEBUGFS_READ_FILE_OPS(rx_queue);
|
||||||
DEBUGFS_READ_FILE_OPS(tx_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(chain_noise);
|
||||||
DEBUGFS_READ_FILE_OPS(tx_power);
|
DEBUGFS_READ_FILE_OPS(tx_power);
|
||||||
DEBUGFS_READ_FILE_OPS(power_save_status);
|
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
|
* 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(data, dbgfs->dir_drv);
|
||||||
DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
|
DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
|
||||||
DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
|
DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
|
||||||
DEBUGFS_ADD_FILE(nvm, data);
|
DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(sram, data);
|
DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(log_event, data);
|
DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
|
||||||
DEBUGFS_ADD_FILE(stations, data);
|
DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(channels, data);
|
DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(status, data);
|
DEBUGFS_ADD_FILE(status, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(interrupt, data);
|
DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(qos, data);
|
DEBUGFS_ADD_FILE(qos, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(led, data);
|
DEBUGFS_ADD_FILE(led, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(sleep_level_override, data);
|
DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(current_sleep_command, data);
|
DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(thermal_throttling, data);
|
DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(disable_ht40, data);
|
DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(rx_statistics, debug);
|
DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(tx_statistics, debug);
|
DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(traffic_log, debug);
|
DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(rx_queue, debug);
|
DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(tx_queue, debug);
|
DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(tx_power, debug);
|
DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(power_save_status, debug);
|
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) {
|
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_rx_stats, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
|
DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(ucode_general_stats, debug);
|
DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(sensitivity, debug);
|
DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
|
||||||
DEBUGFS_ADD_FILE(chain_noise, debug);
|
DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
|
||||||
}
|
}
|
||||||
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
|
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
|
||||||
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
|
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_queue);
|
||||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
|
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_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) {
|
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
|
||||||
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
|
||||||
file_ucode_rx_stats);
|
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 iwl5300_agn_cfg;
|
||||||
extern struct iwl_cfg iwl5100_agn_cfg;
|
extern struct iwl_cfg iwl5100_agn_cfg;
|
||||||
extern struct iwl_cfg iwl5350_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 iwl5100_abg_cfg;
|
||||||
extern struct iwl_cfg iwl5150_agn_cfg;
|
extern struct iwl_cfg iwl5150_agn_cfg;
|
||||||
extern struct iwl_cfg iwl6000h_2agn_cfg;
|
extern struct iwl_cfg iwl5150_abg_cfg;
|
||||||
extern struct iwl_cfg iwl6000h_2abg_cfg;
|
|
||||||
extern struct iwl_cfg iwl6000h_2bg_cfg;
|
|
||||||
extern struct iwl_cfg iwl6000i_2agn_cfg;
|
extern struct iwl_cfg iwl6000i_2agn_cfg;
|
||||||
extern struct iwl_cfg iwl6000i_2abg_cfg;
|
extern struct iwl_cfg iwl6000i_2abg_cfg;
|
||||||
extern struct iwl_cfg iwl6000i_2bg_cfg;
|
extern struct iwl_cfg iwl6000i_2bg_cfg;
|
||||||
extern struct iwl_cfg iwl6000_3agn_cfg;
|
extern struct iwl_cfg iwl6000_3agn_cfg;
|
||||||
extern struct iwl_cfg iwl6050_2agn_cfg;
|
extern struct iwl_cfg iwl6050_2agn_cfg;
|
||||||
extern struct iwl_cfg iwl6050_2abg_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_bgn_cfg;
|
||||||
extern struct iwl_cfg iwl1000_bg_cfg;
|
extern struct iwl_cfg iwl1000_bg_cfg;
|
||||||
|
|
||||||
|
@ -295,9 +292,6 @@ struct iwl_channel_info {
|
||||||
|
|
||||||
/* HT40 channel info */
|
/* HT40 channel info */
|
||||||
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
|
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_flags; /* flags copied from EEPROM */
|
||||||
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
|
||||||
|
|
||||||
|
@ -518,7 +512,6 @@ struct iwl_ht_config {
|
||||||
bool is_ht;
|
bool is_ht;
|
||||||
bool is_40mhz;
|
bool is_40mhz;
|
||||||
bool single_chain_sufficient;
|
bool single_chain_sufficient;
|
||||||
u8 sm_ps;
|
|
||||||
/* BSS related data */
|
/* BSS related data */
|
||||||
u8 extension_chan_offset;
|
u8 extension_chan_offset;
|
||||||
u8 ht_protection;
|
u8 ht_protection;
|
||||||
|
@ -552,23 +545,10 @@ struct iwl_qos_info {
|
||||||
struct iwl_qosparam_cmd def_qos_parm;
|
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_station_entry {
|
||||||
struct iwl_addsta_cmd sta;
|
struct iwl_addsta_cmd sta;
|
||||||
struct iwl_tid_data tid[MAX_TID_COUNT];
|
struct iwl_tid_data tid[MAX_TID_COUNT];
|
||||||
u8 used;
|
u8 used;
|
||||||
u8 ps_status;
|
|
||||||
struct iwl_hw_key keyinfo;
|
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)
|
* 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
|
* in the structure for use by driver. This structure is places in that
|
||||||
* space.
|
* space.
|
||||||
*
|
|
||||||
* At the moment use it for the station's rate scaling information.
|
|
||||||
*/
|
*/
|
||||||
struct iwl_station_priv {
|
struct iwl_station_priv {
|
||||||
struct iwl_lq_sta lq_sta;
|
struct iwl_lq_sta lq_sta;
|
||||||
|
atomic_t pending_frames;
|
||||||
|
bool client;
|
||||||
|
bool asleep;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* one for each uCode image (inst/data, boot/init/runtime) */
|
/* one for each uCode image (inst/data, boot/init/runtime) */
|
||||||
|
@ -1254,6 +1235,7 @@ struct iwl_priv {
|
||||||
/* TX Power */
|
/* TX Power */
|
||||||
s8 tx_power_user_lmt;
|
s8 tx_power_user_lmt;
|
||||||
s8 tx_power_device_lmt;
|
s8 tx_power_device_lmt;
|
||||||
|
s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include "iwl-devtrace.h"
|
#include "iwl-devtrace.h"
|
||||||
|
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
|
||||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
|
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
|
||||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
|
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
|
||||||
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
|
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
|
||||||
|
|
|
@ -14,7 +14,7 @@ static inline void trace_ ## name(proto) {}
|
||||||
#define PRIV_ASSIGN __entry->priv = priv
|
#define PRIV_ASSIGN __entry->priv = priv
|
||||||
|
|
||||||
#undef TRACE_SYSTEM
|
#undef TRACE_SYSTEM
|
||||||
#define TRACE_SYSTEM iwlwifi
|
#define TRACE_SYSTEM iwlwifi_io
|
||||||
|
|
||||||
TRACE_EVENT(iwlwifi_dev_ioread32,
|
TRACE_EVENT(iwlwifi_dev_ioread32,
|
||||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
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)
|
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,
|
TRACE_EVENT(iwlwifi_dev_iowrite32,
|
||||||
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
|
||||||
TP_ARGS(priv, offs, 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)
|
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,
|
TRACE_EVENT(iwlwifi_dev_hcmd,
|
||||||
TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
|
TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
|
||||||
TP_ARGS(priv, hcmd, len, flags),
|
TP_ARGS(priv, hcmd, len, flags),
|
||||||
|
|
|
@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv)
|
||||||
}
|
}
|
||||||
e = (u16 *)priv->eeprom;
|
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);
|
ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
|
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;
|
ret = -ENOENT;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
|
|
||||||
|
|
||||||
/* OTP reads require powered-up chip */
|
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
|
||||||
priv->cfg->ops->lib->apm_ops.init(priv);
|
|
||||||
|
|
||||||
ret = iwl_init_otp_access(priv);
|
ret = iwl_init_otp_access(priv);
|
||||||
if (ret) {
|
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_eeprom = *eeprom_ch;
|
||||||
ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
|
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_flags = eeprom_ch->flags;
|
||||||
ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
|
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
|
* find the highest tx power from all chains for the channel
|
||||||
*/
|
*/
|
||||||
static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
|
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) */
|
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))
|
(enhanced_txpower[element].mimo3_max > max_txpower_avg))
|
||||||
max_txpower_avg = enhanced_txpower[element].mimo3_max;
|
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,
|
static s8 iwl_update_common_txpower(struct iwl_priv *priv,
|
||||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
|
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;
|
struct iwl_channel_info *ch_info;
|
||||||
int ch;
|
int ch;
|
||||||
|
@ -823,25 +828,25 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv,
|
||||||
if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
|
if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX)
|
||||||
is_ht40 = true;
|
is_ht40 = true;
|
||||||
max_txpower_avg =
|
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;
|
ch_info = priv->channel_info;
|
||||||
|
|
||||||
for (ch = 0; ch < priv->channel_count; ch++) {
|
for (ch = 0; ch < priv->channel_count; ch++) {
|
||||||
/* find matching band and update tx power if needed */
|
/* find matching band and update tx power if needed */
|
||||||
if ((ch_info->band == enhinfo[section].band) &&
|
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 */
|
/* Update regulatory-based run-time data */
|
||||||
ch_info->max_power_avg = ch_info->curr_txpow =
|
ch_info->max_power_avg = ch_info->curr_txpow =
|
||||||
max_txpower_avg;
|
max_txpower_avg;
|
||||||
ch_info->scan_power = max_txpower_avg;
|
ch_info->scan_power = max_txpower_avg;
|
||||||
}
|
}
|
||||||
if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
|
if ((ch_info->band == enhinfo[section].band) && is_ht40 &&
|
||||||
ch_info->ht40_max_power_avg &&
|
|
||||||
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
||||||
/* Update regulatory-based run-time data */
|
/* Update regulatory-based run-time data */
|
||||||
ch_info->ht40_max_power_avg = max_txpower_avg;
|
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++;
|
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,
|
static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
|
||||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
|
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;
|
struct iwl_channel_info *ch_info;
|
||||||
int ch;
|
int ch;
|
||||||
|
@ -863,7 +868,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv,
|
||||||
|
|
||||||
channel = enhinfo[section].iwl_eeprom_section_channel[element];
|
channel = enhinfo[section].iwl_eeprom_section_channel[element];
|
||||||
max_txpower_avg =
|
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;
|
ch_info = priv->channel_info;
|
||||||
for (ch = 0; ch < priv->channel_count; ch++) {
|
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;
|
ch_info->scan_power = max_txpower_avg;
|
||||||
}
|
}
|
||||||
if ((enhinfo[section].is_ht40) &&
|
if ((enhinfo[section].is_ht40) &&
|
||||||
(ch_info->ht40_max_power_avg) &&
|
|
||||||
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
(ch_info->ht40_max_power_avg < max_txpower_avg)) {
|
||||||
/* Update regulatory-based run-time data */
|
/* Update regulatory-based run-time data */
|
||||||
ch_info->ht40_max_power_avg = max_txpower_avg;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -901,6 +904,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
|
||||||
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
|
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
s8 max_txpower_avg; /* (dBm) */
|
s8 max_txpower_avg; /* (dBm) */
|
||||||
|
s8 max_txpower_in_half_dbm; /* (half-dBm) */
|
||||||
|
|
||||||
/* Loop through all the sections
|
/* Loop through all the sections
|
||||||
* adjust bands and channel's max tx power
|
* 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 *)
|
enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *)
|
||||||
iwl_eeprom_query_addr(priv, offset);
|
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++) {
|
for (element = 0; element < eeprom_section_count; element++) {
|
||||||
if (enhinfo[section].is_common)
|
if (enhinfo[section].is_common)
|
||||||
max_txpower_avg =
|
max_txpower_avg =
|
||||||
iwl_update_common_txpower(priv,
|
iwl_update_common_txpower(priv,
|
||||||
enhanced_txpower, section, element);
|
enhanced_txpower, section,
|
||||||
|
element,
|
||||||
|
&max_txpower_in_half_dbm);
|
||||||
else
|
else
|
||||||
max_txpower_avg =
|
max_txpower_avg =
|
||||||
iwl_update_channel_txpower(priv,
|
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
|
/* Update the tx_power_user_lmt to the highest power
|
||||||
* supported by any channel */
|
* supported by any channel */
|
||||||
if (max_txpower_avg > priv->tx_power_user_lmt)
|
if (max_txpower_avg > priv->tx_power_user_lmt)
|
||||||
priv->tx_power_user_lmt = max_txpower_avg;
|
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
|
* 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
|
* into individual structures; each one is 8 bytes in size and contain the
|
||||||
* following information
|
* 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_a_max_pwr: chain a max power in 1/2 dBm
|
||||||
* @chain_b_max_pwr: chain b 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
|
* @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
|
* @mimo2_max_pwr: mimo2 max power in 1/2 dBm
|
||||||
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
|
* @mimo3_max_pwr: mimo3 max power in 1/2 dBm
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct iwl_eeprom_enhanced_txpwr {
|
struct iwl_eeprom_enhanced_txpwr {
|
||||||
u16 reserved;
|
u16 common;
|
||||||
s8 chain_a_max;
|
s8 chain_a_max;
|
||||||
s8 chain_b_max;
|
s8 chain_b_max;
|
||||||
s8 chain_c_max;
|
s8 chain_c_max;
|
||||||
s8 reserved1;
|
s8 reserved;
|
||||||
s8 mimo2_max;
|
s8 mimo2_max;
|
||||||
s8 mimo3_max;
|
s8 mimo3_max;
|
||||||
} __attribute__ ((packed));
|
} __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)
|
static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
|
||||||
{
|
{
|
||||||
trace_iwlwifi_dev_iowrite32(priv, ofs, 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)
|
void iwl_leds_init(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
priv->last_blink_rate = 0;
|
priv->last_blink_rate = 0;
|
||||||
priv->led_tpt = 0;
|
|
||||||
priv->last_blink_time = 0;
|
priv->last_blink_time = 0;
|
||||||
priv->allow_blinking = 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");
|
IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
|
||||||
/* make request to retrieve statistics information */
|
/* 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 */
|
/* Reschedule the ct_kill wait timer */
|
||||||
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
|
mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
|
||||||
jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
|
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)|
|
(rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
|
||||||
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -635,6 +636,24 @@ void iwl_rx_statistics(struct iwl_priv *priv,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_rx_statistics);
|
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 PERFECT_RSSI (-20) /* dBm */
|
||||||
#define WORST_RSSI (-95) /* dBm */
|
#define WORST_RSSI (-95) /* dBm */
|
||||||
#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
|
#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;
|
struct iwl4965_rx_mpdu_res_start *amsdu;
|
||||||
u32 len;
|
u32 len;
|
||||||
u32 ampdu_status;
|
u32 ampdu_status;
|
||||||
u16 fc;
|
|
||||||
u32 rate_n_flags;
|
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);
|
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,
|
iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
|
||||||
rxb, &rx_status);
|
rxb, &rx_status);
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_rx_reply_rx);
|
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);
|
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;
|
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 &= ~STA_FLG_PWR_SAVE_MSK;
|
||||||
priv->stations[sta_id].sta.station_flags_msk = 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.sta.modify_mask = 0;
|
||||||
|
priv->stations[sta_id].sta.sleep_tx_count = 0;
|
||||||
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||||
|
|
||||||
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
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 ??? */
|
unsigned long flags;
|
||||||
u8 sta_id = iwl_find_station(priv, addr);
|
|
||||||
|
|
||||||
if (sta_id != IWL_INVALID_STATION) {
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
u8 sta_awake = priv->stations[sta_id].
|
priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK;
|
||||||
ps_status == STA_PS_STATUS_WAKE;
|
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)
|
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
int iwl_sta_rx_agg_start(struct iwl_priv *priv,
|
||||||
const u8 *addr, int tid, u16 ssn);
|
const u8 *addr, int tid, u16 ssn);
|
||||||
int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
|
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__ */
|
#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_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
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_tx_queue *txq;
|
||||||
struct iwl_queue *q;
|
struct iwl_queue *q;
|
||||||
struct iwl_device_cmd *out_cmd;
|
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);
|
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);
|
txq_id = skb_get_queue_mapping(skb);
|
||||||
if (ieee80211_is_data_qos(fc)) {
|
if (ieee80211_is_data_qos(fc)) {
|
||||||
qc = ieee80211_get_qos_ctl(hdr);
|
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);
|
ret = iwl_txq_update_write_ptr(priv, txq);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
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)
|
if (ret)
|
||||||
return 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)) {
|
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))
|
if (iwl_within_ct_kill_margin(priv))
|
||||||
iwl_tt_enter_ct_kill(priv);
|
iwl_tt_enter_ct_kill(priv);
|
||||||
else {
|
else {
|
||||||
|
@ -1075,6 +1106,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
||||||
return ret ? ret : idx;
|
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)
|
int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
|
||||||
{
|
{
|
||||||
struct iwl_tx_queue *txq = &priv->txq[txq_id];
|
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)) {
|
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||||
|
|
||||||
tx_info = &txq->txb[txq->q.read_ptr];
|
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;
|
tx_info->skb[0] = NULL;
|
||||||
|
|
||||||
if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
|
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) {
|
if (tid_data->tfds_in_queue == 0) {
|
||||||
IWL_DEBUG_HT(priv, "HW queue is empty\n");
|
IWL_DEBUG_HT(priv, "HW queue is empty\n");
|
||||||
tid_data->agg.state = IWL_AGG_ON;
|
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 {
|
} else {
|
||||||
IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
|
IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
|
||||||
tid_data->tfds_in_queue);
|
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)
|
if (ret)
|
||||||
return 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;
|
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,
|
priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
|
||||||
ssn, tx_fifo);
|
ssn, tx_fifo);
|
||||||
tid_data->agg.state = IWL_AGG_OFF;
|
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;
|
break;
|
||||||
case IWL_EMPTYING_HW_QUEUE_ADDBA:
|
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) {
|
if (tid_data->tfds_in_queue == 0) {
|
||||||
IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
|
IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
|
||||||
tid_data->agg.state = IWL_AGG_ON;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1483,7 +1483,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
|
||||||
tasklet_kill(&priv->irq_tasklet);
|
tasklet_kill(&priv->irq_tasklet);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
static const char *desc_lookup(int i)
|
static const char *desc_lookup(int i)
|
||||||
{
|
{
|
||||||
switch (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);
|
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 */
|
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
|
||||||
#define IWL3945_MAX_EVENT_LOG_SIZE (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 base; /* SRAM byte address of event log header */
|
||||||
u32 capacity; /* event log capacity in # entries */
|
u32 capacity; /* event log capacity in # entries */
|
||||||
|
@ -1658,8 +1689,17 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
size, num_wraps);
|
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,
|
/* if uCode has wrapped back to top of log, start at the oldest entry,
|
||||||
* i.e the next one that uCode would fill. */
|
* 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 */
|
/* (then/else) start at top of log */
|
||||||
iwl3945_print_event_log(priv, 0, next_entry, mode);
|
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
|
#else
|
||||||
void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
|
iwl3945_print_last_event_logs(priv, capacity, num_wraps,
|
||||||
{
|
next_entry, size, mode);
|
||||||
}
|
|
||||||
|
|
||||||
void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
u32 inta, handled = 0;
|
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 = priv->rates_mask;
|
||||||
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_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)) {
|
if (iwl_is_associated(priv)) {
|
||||||
struct iwl3945_rxon_cmd *active_rxon =
|
struct iwl3945_rxon_cmd *active_rxon =
|
||||||
|
@ -3650,7 +3700,7 @@ static ssize_t show_statistics(struct device *d,
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
rc = iwl_send_statistics_request(priv, 0);
|
rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -3905,10 +3955,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
|
||||||
BIT(NL80211_IFTYPE_STATION) |
|
BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_ADHOC);
|
BIT(NL80211_IFTYPE_ADHOC);
|
||||||
|
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY |
|
||||||
|
WIPHY_FLAG_DISABLE_BEACON_HINTS;
|
||||||
/* Firmware does not support this */
|
|
||||||
hw->wiphy->disable_beacon_hints = true;
|
|
||||||
|
|
||||||
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
|
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
|
||||||
/* we create the 802.11 header and a zero-length SSID element */
|
/* we create the 802.11 header and a zero-length SSID element */
|
||||||
|
|
|
@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void)
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_WORLD_ROAM:
|
case HWSIM_REGTEST_WORLD_ROAM:
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_01);
|
&hwsim_world_regdom_custom_01);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_CUSTOM_WORLD:
|
case HWSIM_REGTEST_CUSTOM_WORLD:
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_01);
|
&hwsim_world_regdom_custom_01);
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_CUSTOM_WORLD_2:
|
case HWSIM_REGTEST_CUSTOM_WORLD_2:
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_01);
|
&hwsim_world_regdom_custom_01);
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_02);
|
&hwsim_world_regdom_custom_02);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_STRICT_ALL:
|
case HWSIM_REGTEST_STRICT_ALL:
|
||||||
hw->wiphy->strict_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_STRICT_FOLLOW:
|
case HWSIM_REGTEST_STRICT_FOLLOW:
|
||||||
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
|
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
hw->wiphy->strict_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||||
break;
|
break;
|
||||||
case HWSIM_REGTEST_ALL:
|
case HWSIM_REGTEST_ALL:
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_01);
|
&hwsim_world_regdom_custom_01);
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
hw->wiphy->custom_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy,
|
wiphy_apply_custom_regulatory(hw->wiphy,
|
||||||
&hwsim_world_regdom_custom_02);
|
&hwsim_world_regdom_custom_02);
|
||||||
} else if (i == 4)
|
} else if (i == 4)
|
||||||
hw->wiphy->strict_regulatory = true;
|
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
* For now, disable PS by default because it affects
|
||||||
* link stability significantly.
|
* 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->conf_mutex);
|
||||||
mutex_init(&priv->eeprom_mutex);
|
mutex_init(&priv->eeprom_mutex);
|
||||||
|
|
|
@ -83,11 +83,11 @@ MODULE_PARM_DESC(roamdelta,
|
||||||
"set roaming tendency: 0=aggressive, 1=moderate, "
|
"set roaming tendency: 0=aggressive, 1=moderate, "
|
||||||
"2=conservative (default: moderate)");
|
"2=conservative (default: moderate)");
|
||||||
|
|
||||||
static int modparam_workaround_interval = 500;
|
static int modparam_workaround_interval;
|
||||||
module_param_named(workaround_interval, modparam_workaround_interval,
|
module_param_named(workaround_interval, modparam_workaround_interval,
|
||||||
int, 0444);
|
int, 0444);
|
||||||
MODULE_PARM_DESC(workaround_interval,
|
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 */
|
/* 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));
|
le32_to_cpu(u.get_c->status));
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
|
||||||
|
|
||||||
ret = le32_to_cpu(u.get_c->len);
|
ret = le32_to_cpu(u.get_c->len);
|
||||||
if (ret > *len)
|
if (ret > *len)
|
||||||
*len = ret;
|
*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)
|
if (ret < 0)
|
||||||
devdbg(dev, "rndis_query_oid(%s): device returned "
|
devdbg(dev, "rndis_query_oid(%s): device returned "
|
||||||
"error, 0x%08x (%d)", oid_to_string(oid),
|
"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.
|
/* Workaround transfer stalls on poor quality links.
|
||||||
* TODO: find right way to fix these stalls (as stalls do not happen
|
* TODO: find right way to fix these stalls (as stalls do not happen
|
||||||
* with ndiswrapper/windows driver). */
|
* 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.
|
/* Decrease stats worker interval to catch stalls.
|
||||||
* faster. Faster than 400-500ms causes packet loss,
|
* faster. Faster than 400-500ms causes packet loss,
|
||||||
* Slower doesn't catch stalls fast enough.
|
* 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) },
|
{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Amit */
|
/* Amit */
|
||||||
{ USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ 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 */
|
/* ASUS */
|
||||||
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0b05, 0x1732), 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, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0b05, 0x1760), 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, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* AzureWave */
|
/* AzureWave */
|
||||||
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x13d3, 0x3262), 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, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Belkin */
|
/* Belkin */
|
||||||
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x050d, 0x805c), 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 */
|
/* Buffalo */
|
||||||
{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0411, 0x012e), 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 */
|
/* Conceptronic */
|
||||||
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x14b2, 0x3c07), 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, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07aa, 0x003c), 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, 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, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* D-Link */
|
/* 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, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07d1, 0x3c11), 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, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Edimax */
|
/* Edimax */
|
||||||
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Encore */
|
/* Encore */
|
||||||
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ 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 */
|
/* EnGenius */
|
||||||
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1740, 0x9702), 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, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1740, 0x9705), 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, 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) },
|
{ USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Gemtek */
|
/* Gemtek */
|
||||||
{ USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ 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, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* I-O DATA */
|
/* I-O DATA */
|
||||||
|
{ USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x04bb, 0x0945), 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 */
|
/* LevelOne */
|
||||||
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1740, 0x0615), 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 */
|
/* Motorola */
|
||||||
{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x100d, 0x9032), 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 */
|
/* Ovislink */
|
||||||
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
/* Para */
|
||||||
|
{ USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Pegatron */
|
/* Pegatron */
|
||||||
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1d4d, 0x000c), 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 */
|
/* Quanta */
|
||||||
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Ralink */
|
/* 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, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x148f, 0x2870), 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, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0df6, 0x003f), 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, 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, 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 */
|
/* SMC */
|
||||||
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x083a, 0x7511), 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, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x083a, 0xa512), 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, 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, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Sparklan */
|
/* 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, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x5a57, 0x0282), 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, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Zyxel */
|
/* Zyxel */
|
||||||
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ 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);
|
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
||||||
unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
|
unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
|
||||||
u8 rate_idx, rate_flags, retry_rates;
|
u8 rate_idx, rate_flags, retry_rates;
|
||||||
|
u8 skbdesc_flags = skbdesc->flags;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
|
@ -287,12 +288,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only send the status report to mac80211 when TX status was
|
* Only send the status report to mac80211 when it's a frame
|
||||||
* requested by it. If this was a extra frame coming through
|
* that originated in mac80211. If this was a extra frame coming
|
||||||
* a mac80211 library call (RTS/CTS) then we should not send the
|
* through a mac80211 library call (RTS/CTS) then we should not
|
||||||
* status report back.
|
* 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);
|
ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
|
||||||
else
|
else
|
||||||
dev_kfree_skb_irq(entry->skb);
|
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
|
* rt2x00queue_write_tx_frame - Write TX frame to hardware
|
||||||
* @queue: Queue over which the frame should be send
|
* @queue: Queue over which the frame should be send
|
||||||
* @skb: The skb to 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
|
* 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 = 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_RTS_CTS;
|
||||||
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
|
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)
|
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
||||||
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
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,
|
frag_skb->data, data_length, tx_info,
|
||||||
(struct ieee80211_rts *)(skb->data));
|
(struct ieee80211_rts *)(skb->data));
|
||||||
|
|
||||||
retval = rt2x00queue_write_tx_frame(queue, skb);
|
retval = rt2x00queue_write_tx_frame(queue, skb, true);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
|
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;
|
goto exit_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rt2x00queue_write_tx_frame(queue, skb))
|
if (rt2x00queue_write_tx_frame(queue, skb, false))
|
||||||
goto exit_fail;
|
goto exit_fail;
|
||||||
|
|
||||||
if (rt2x00queue_threshold(queue))
|
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);
|
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 ieee80211_tx_info *tx_info;
|
||||||
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
|
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_idx = rate_idx;
|
||||||
skbdesc->tx_rate_flags = rate_flags;
|
skbdesc->tx_rate_flags = rate_flags;
|
||||||
|
|
||||||
|
if (local)
|
||||||
|
skbdesc->flags |= SKBDESC_NOT_MAC80211;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When hardware encryption is supported, and this frame
|
* When hardware encryption is supported, and this frame
|
||||||
* is to be encrypted, we should strip the IV/EIV data from
|
* 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.
|
* mac80211 but was stripped for processing by the driver.
|
||||||
* @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
|
* @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
|
||||||
* the padded bytes are located between header and payload.
|
* 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 {
|
enum skb_frame_desc_flags {
|
||||||
SKBDESC_DMA_MAPPED_RX = 1 << 0,
|
SKBDESC_DMA_MAPPED_RX = 1 << 0,
|
||||||
SKBDESC_DMA_MAPPED_TX = 1 << 1,
|
SKBDESC_DMA_MAPPED_TX = 1 << 1,
|
||||||
SKBDESC_IV_STRIPPED = 1 << 2,
|
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);
|
void (*set_power)(bool enable);
|
||||||
int irq;
|
int irq;
|
||||||
|
bool use_eeprom;
|
||||||
|
|
||||||
enum wl1251_state state;
|
enum wl1251_state state;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
@ -354,6 +355,8 @@ struct wl1251 {
|
||||||
/* is firmware in elp mode */
|
/* is firmware in elp mode */
|
||||||
bool elp;
|
bool elp;
|
||||||
|
|
||||||
|
struct delayed_work elp_work;
|
||||||
|
|
||||||
/* we can be in psm, but not in elp, we have to differentiate */
|
/* we can be in psm, but not in elp, we have to differentiate */
|
||||||
bool psm;
|
bool psm;
|
||||||
|
|
||||||
|
@ -374,6 +377,8 @@ struct wl1251 {
|
||||||
u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
|
u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
|
||||||
struct wl1251_rx_descriptor *rx_descriptor;
|
struct wl1251_rx_descriptor *rx_descriptor;
|
||||||
|
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
|
||||||
u32 chip_id;
|
u32 chip_id;
|
||||||
char fw_ver[21];
|
char fw_ver[21];
|
||||||
};
|
};
|
||||||
|
|
|
@ -494,7 +494,7 @@ out:
|
||||||
return ret;
|
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;
|
struct acx_beacon_filter_option *beacon_filter;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -507,7 +507,7 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
beacon_filter->enable = 0;
|
beacon_filter->enable = enable_filter;
|
||||||
beacon_filter->max_num_beacons = 0;
|
beacon_filter->max_num_beacons = 0;
|
||||||
|
|
||||||
ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
|
ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
|
||||||
|
@ -525,6 +525,7 @@ out:
|
||||||
int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
|
int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
|
||||||
{
|
{
|
||||||
struct acx_beacon_filter_ie_table *ie_table;
|
struct acx_beacon_filter_ie_table *ie_table;
|
||||||
|
int idx = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wl1251_debug(DEBUG_ACX, "acx beacon filter table");
|
wl1251_debug(DEBUG_ACX, "acx beacon filter table");
|
||||||
|
@ -535,8 +536,10 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ie_table->num_ie = 0;
|
/* configure default beacon pass-through rules */
|
||||||
memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
|
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,
|
ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
|
||||||
ie_table, sizeof(*ie_table));
|
ie_table, sizeof(*ie_table));
|
||||||
|
@ -550,6 +553,35 @@ out:
|
||||||
return ret;
|
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)
|
int wl1251_acx_sg_enable(struct wl1251 *wl)
|
||||||
{
|
{
|
||||||
struct acx_bt_wlan_coex *pta;
|
struct acx_bt_wlan_coex *pta;
|
||||||
|
@ -916,3 +948,31 @@ out:
|
||||||
kfree(mem_conf);
|
kfree(mem_conf);
|
||||||
return ret;
|
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_MAX_VENDOR_SPECIFIC_IE_NUM * \
|
||||||
BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE))
|
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_beacon_filter_ie_table {
|
||||||
struct acx_header header;
|
struct acx_header header;
|
||||||
|
|
||||||
|
@ -458,6 +463,16 @@ struct acx_beacon_filter_ie_table {
|
||||||
u8 pad[3];
|
u8 pad[3];
|
||||||
} __attribute__ ((packed));
|
} __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 {
|
enum {
|
||||||
SG_ENABLE = 0,
|
SG_ENABLE = 0,
|
||||||
SG_DISABLE,
|
SG_DISABLE,
|
||||||
|
@ -1134,6 +1149,23 @@ struct wl1251_acx_mem_map {
|
||||||
u32 num_rx_mem_blocks;
|
u32 num_rx_mem_blocks;
|
||||||
} __attribute__ ((packed));
|
} __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)
|
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_group_address_tbl(struct wl1251 *wl);
|
||||||
int wl1251_acx_service_period_timeout(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_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_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_enable(struct wl1251 *wl);
|
||||||
int wl1251_acx_sg_cfg(struct wl1251 *wl);
|
int wl1251_acx_sg_cfg(struct wl1251 *wl);
|
||||||
int wl1251_acx_cca_threshold(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_tsf_info(struct wl1251 *wl, u64 *mactime);
|
||||||
int wl1251_acx_rate_policies(struct wl1251 *wl);
|
int wl1251_acx_rate_policies(struct wl1251 *wl);
|
||||||
int wl1251_acx_mem_cfg(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__ */
|
#endif /* __WL1251_ACX_H__ */
|
||||||
|
|
|
@ -296,8 +296,12 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
||||||
WL1251_ACX_INTR_INIT_COMPLETE;
|
WL1251_ACX_INTR_INIT_COMPLETE;
|
||||||
wl1251_boot_target_enable_interrupts(wl);
|
wl1251_boot_target_enable_interrupts(wl);
|
||||||
|
|
||||||
/* unmask all mbox events */
|
wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID |
|
||||||
wl->event_mask = 0xffffffff;
|
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);
|
ret = wl1251_event_unmask(wl);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -314,8 +318,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
|
||||||
static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
||||||
{
|
{
|
||||||
int addr, chunk_num, partition_limit;
|
int addr, chunk_num, partition_limit;
|
||||||
size_t fw_data_len;
|
size_t fw_data_len, len;
|
||||||
u8 *p;
|
u8 *p, *buf;
|
||||||
|
|
||||||
/* whal_FwCtrl_LoadFwImageSm() */
|
/* whal_FwCtrl_LoadFwImageSm() */
|
||||||
|
|
||||||
|
@ -334,6 +338,12 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
||||||
return -EIO;
|
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_set_partition(wl, WL1251_PART_DOWN_MEM_START,
|
||||||
WL1251_PART_DOWN_MEM_SIZE,
|
WL1251_PART_DOWN_MEM_SIZE,
|
||||||
WL1251_PART_DOWN_REG_START,
|
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;
|
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
|
||||||
wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
|
||||||
p, addr);
|
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++;
|
chunk_num++;
|
||||||
}
|
}
|
||||||
|
@ -372,9 +386,16 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl)
|
||||||
/* 10.4 upload the last chunk */
|
/* 10.4 upload the last chunk */
|
||||||
addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
|
addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE;
|
||||||
p = wl->fw + FW_HDR_SIZE + 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",
|
wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
|
||||||
fw_data_len % CHUNK_SIZE, p, addr);
|
len, p, addr);
|
||||||
wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
|
wl1251_mem_write(wl, addr, buf, len);
|
||||||
|
|
||||||
|
kfree(buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -473,6 +494,11 @@ int wl1251_boot(struct wl1251 *wl)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* 2. start processing NVS file */
|
/* 2. start processing NVS file */
|
||||||
|
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);
|
ret = wl1251_boot_upload_nvs(wl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -480,6 +506,7 @@ int wl1251_boot(struct wl1251 *wl)
|
||||||
/* write firmware's last address (ie. it's length) to
|
/* write firmware's last address (ie. it's length) to
|
||||||
* ACX_EEPROMLESS_IND_REG */
|
* ACX_EEPROMLESS_IND_REG */
|
||||||
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
|
wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
|
||||||
|
}
|
||||||
|
|
||||||
/* 6. read the EEPROM parameters */
|
/* 6. read the EEPROM parameters */
|
||||||
tmp = wl1251_reg_read32(wl, SCR_PAD2);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,8 @@ int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
|
||||||
{
|
{
|
||||||
int ret;
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -364,6 +365,11 @@ int wl1251_hw_init(struct wl1251 *wl)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_free_data_path;
|
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 */
|
/* Beacon filtering */
|
||||||
ret = wl1251_hw_init_beacon_filter(wl);
|
ret = wl1251_hw_init_beacon_filter(wl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include "wl1251.h"
|
#include "wl1251.h"
|
||||||
#include "wl12xx_80211.h"
|
#include "wl12xx_80211.h"
|
||||||
|
@ -83,7 +84,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl)
|
||||||
}
|
}
|
||||||
|
|
||||||
wl->fw_len = fw->size;
|
wl->fw_len = fw->size;
|
||||||
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
|
wl->fw = vmalloc(wl->fw_len);
|
||||||
|
|
||||||
if (!wl->fw) {
|
if (!wl->fw) {
|
||||||
wl1251_error("could not allocate memory for the firmware");
|
wl1251_error("could not allocate memory for the firmware");
|
||||||
|
@ -211,9 +212,10 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WL1251_IRQ_LOOP_COUNT 10
|
||||||
static void wl1251_irq_work(struct work_struct *work)
|
static void wl1251_irq_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
u32 intr;
|
u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
|
||||||
struct wl1251 *wl =
|
struct wl1251 *wl =
|
||||||
container_of(work, struct wl1251, irq_work);
|
container_of(work, struct wl1251, irq_work);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -234,14 +236,16 @@ static void wl1251_irq_work(struct work_struct *work)
|
||||||
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
|
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
|
||||||
wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
|
wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
|
||||||
|
|
||||||
|
do {
|
||||||
if (wl->data_path) {
|
if (wl->data_path) {
|
||||||
wl->rx_counter =
|
wl->rx_counter = wl1251_mem_read32(
|
||||||
wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
|
wl, wl->data_path->rx_control_addr);
|
||||||
|
|
||||||
/* We handle a frmware bug here */
|
/* We handle a frmware bug here */
|
||||||
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
|
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
|
||||||
case 0:
|
case 0:
|
||||||
wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
|
wl1251_debug(DEBUG_IRQ,
|
||||||
|
"RX: FW and host in sync");
|
||||||
intr &= ~WL1251_ACX_INTR_RX0_DATA;
|
intr &= ~WL1251_ACX_INTR_RX0_DATA;
|
||||||
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
intr &= ~WL1251_ACX_INTR_RX1_DATA;
|
||||||
break;
|
break;
|
||||||
|
@ -256,24 +260,22 @@ static void wl1251_irq_work(struct work_struct *work)
|
||||||
intr |= WL1251_ACX_INTR_RX1_DATA;
|
intr |= WL1251_ACX_INTR_RX1_DATA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wl1251_warning("RX: FW and host out of sync: %d",
|
wl1251_warning(
|
||||||
|
"RX: FW and host out of sync: %d",
|
||||||
wl->rx_counter - wl->rx_handled);
|
wl->rx_counter - wl->rx_handled);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl->rx_handled = wl->rx_counter;
|
wl->rx_handled = wl->rx_counter;
|
||||||
|
|
||||||
|
wl1251_debug(DEBUG_IRQ, "RX counter: %d",
|
||||||
wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
|
wl->rx_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
intr &= wl->intr_mask;
|
intr &= wl->intr_mask;
|
||||||
|
|
||||||
if (intr == 0) {
|
if (intr == 0) {
|
||||||
wl1251_debug(DEBUG_IRQ, "INTR is 0");
|
wl1251_debug(DEBUG_IRQ, "INTR is 0");
|
||||||
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
|
|
||||||
~(wl->intr_mask));
|
|
||||||
|
|
||||||
goto out_sleep;
|
goto out_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +294,10 @@ static void wl1251_irq_work(struct work_struct *work)
|
||||||
wl1251_tx_complete(wl);
|
wl1251_tx_complete(wl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
|
if (intr & (WL1251_ACX_INTR_EVENT_A |
|
||||||
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
|
WL1251_ACX_INTR_EVENT_B)) {
|
||||||
|
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
|
||||||
|
intr);
|
||||||
if (intr & WL1251_ACX_INTR_EVENT_A)
|
if (intr & WL1251_ACX_INTR_EVENT_A)
|
||||||
wl1251_event_handle(wl, 0);
|
wl1251_event_handle(wl, 0);
|
||||||
else
|
else
|
||||||
|
@ -301,11 +305,17 @@ static void wl1251_irq_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
|
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
|
||||||
wl1251_debug(DEBUG_IRQ, "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));
|
if (--ctr == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
|
||||||
|
} while (intr);
|
||||||
|
|
||||||
out_sleep:
|
out_sleep:
|
||||||
|
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
|
||||||
wl1251_ps_elp_sleep(wl);
|
wl1251_ps_elp_sleep(wl);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -509,6 +519,12 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
|
||||||
conf->type, conf->mac_addr);
|
conf->type, conf->mac_addr);
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
|
if (wl->vif) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl->vif = conf->vif;
|
||||||
|
|
||||||
switch (conf->type) {
|
switch (conf->type) {
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
|
@ -538,7 +554,12 @@ out:
|
||||||
static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
|
static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_if_init_conf *conf)
|
struct ieee80211_if_init_conf *conf)
|
||||||
{
|
{
|
||||||
|
struct wl1251 *wl = hw->priv;
|
||||||
|
|
||||||
|
mutex_lock(&wl->mutex);
|
||||||
wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
|
wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
|
||||||
|
wl->vif = NULL;
|
||||||
|
mutex_unlock(&wl->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wl1251_build_null_data(struct wl1251 *wl)
|
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);
|
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
|
||||||
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
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,
|
return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
|
||||||
sizeof(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.bssid, wl->bssid, ETH_ALEN);
|
||||||
memcpy(template.ta, wl->mac_addr, 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);
|
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
|
||||||
|
|
||||||
return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
|
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->beacon_int = bss_conf->beacon_int;
|
||||||
wl->dtim_period = bss_conf->dtim_period;
|
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;
|
wl->aid = bss_conf->aid;
|
||||||
|
|
||||||
ret = wl1251_build_ps_poll(wl, wl->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 |
|
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||||
IEEE80211_HW_NOISE_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->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||||
wl->hw->wiphy->max_scan_ssids = 1;
|
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);
|
skb_queue_head_init(&wl->tx_queue);
|
||||||
|
|
||||||
INIT_WORK(&wl->filter_work, wl1251_filter_work);
|
INIT_WORK(&wl->filter_work, wl1251_filter_work);
|
||||||
|
INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
|
||||||
wl->channel = WL1251_DEFAULT_CHANNEL;
|
wl->channel = WL1251_DEFAULT_CHANNEL;
|
||||||
wl->scanning = false;
|
wl->scanning = false;
|
||||||
wl->default_key = 0;
|
wl->default_key = 0;
|
||||||
|
@ -1372,6 +1399,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
|
||||||
wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
|
wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
|
||||||
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
||||||
wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
|
wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
|
||||||
|
wl->vif = NULL;
|
||||||
|
|
||||||
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
|
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
|
||||||
wl->tx_frames[i] = NULL;
|
wl->tx_frames[i] = NULL;
|
||||||
|
@ -1413,7 +1441,7 @@ int wl1251_free_hw(struct wl1251 *wl)
|
||||||
|
|
||||||
kfree(wl->target_mem_map);
|
kfree(wl->target_mem_map);
|
||||||
kfree(wl->data_path);
|
kfree(wl->data_path);
|
||||||
kfree(wl->fw);
|
vfree(wl->fw);
|
||||||
wl->fw = NULL;
|
wl->fw = NULL;
|
||||||
kfree(wl->nvs);
|
kfree(wl->nvs);
|
||||||
wl->nvs = NULL;
|
wl->nvs = NULL;
|
||||||
|
|
|
@ -28,17 +28,41 @@
|
||||||
|
|
||||||
#define WL1251_WAKEUP_TIMEOUT 2000
|
#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 */
|
/* Routines to toggle sleep mode while in ELP */
|
||||||
void wl1251_ps_elp_sleep(struct wl1251 *wl)
|
void wl1251_ps_elp_sleep(struct wl1251 *wl)
|
||||||
{
|
{
|
||||||
if (wl->elp || !wl->psm)
|
unsigned long delay;
|
||||||
return;
|
|
||||||
|
|
||||||
wl1251_debug(DEBUG_PSM, "chip to elp");
|
if (wl->psm) {
|
||||||
|
cancel_delayed_work(&wl->elp_work);
|
||||||
wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
|
||||||
|
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
|
||||||
wl->elp = true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int wl1251_ps_elp_wakeup(struct wl1251 *wl)
|
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:
|
case STATION_POWER_SAVE_MODE:
|
||||||
wl1251_debug(DEBUG_PSM, "entering psm");
|
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,
|
ret = wl1251_acx_wake_up_conditions(wl,
|
||||||
WAKE_UP_EVENT_DTIM_BITMAP,
|
WAKE_UP_EVENT_DTIM_BITMAP,
|
||||||
wl->listen_int);
|
wl->listen_int);
|
||||||
|
@ -142,6 +171,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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,
|
ret = wl1251_acx_wake_up_conditions(wl,
|
||||||
WAKE_UP_EVENT_DTIM_BITMAP,
|
WAKE_UP_EVENT_DTIM_BITMAP,
|
||||||
wl->listen_int);
|
wl->listen_int);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
|
int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
|
||||||
void wl1251_ps_elp_sleep(struct wl1251 *wl);
|
void wl1251_ps_elp_sleep(struct wl1251 *wl);
|
||||||
int wl1251_ps_elp_wakeup(struct wl1251 *wl);
|
int wl1251_ps_elp_wakeup(struct wl1251 *wl);
|
||||||
|
void wl1251_elp_work(struct work_struct *work);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __WL1251_PS_H__ */
|
#endif /* __WL1251_PS_H__ */
|
||||||
|
|
|
@ -370,6 +370,7 @@ enum wl12xx_acx_int_reg {
|
||||||
EEPROM location specified in the EE_ADDR register.
|
EEPROM location specified in the EE_ADDR register.
|
||||||
The Wlan hardware hardware clears this bit automatically.
|
The Wlan hardware hardware clears this bit automatically.
|
||||||
*===============================================*/
|
*===============================================*/
|
||||||
|
#define EE_CTL (REGISTERS_BASE + 0x2000)
|
||||||
#define ACX_EE_CTL_REG EE_CTL
|
#define ACX_EE_CTL_REG EE_CTL
|
||||||
#define EE_WRITE 0x00000001ul
|
#define EE_WRITE 0x00000001ul
|
||||||
#define EE_READ 0x00000002ul
|
#define EE_READ 0x00000002ul
|
||||||
|
@ -380,6 +381,7 @@ enum wl12xx_acx_int_reg {
|
||||||
This register specifies the address
|
This register specifies the address
|
||||||
within the EEPROM from/to which to read/write data.
|
within the EEPROM from/to which to read/write data.
|
||||||
===============================================*/
|
===============================================*/
|
||||||
|
#define EE_ADDR (REGISTERS_BASE + 0x2008)
|
||||||
#define ACX_EE_ADDR_REG EE_ADDR
|
#define ACX_EE_ADDR_REG EE_ADDR
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
|
@ -389,8 +391,12 @@ enum wl12xx_acx_int_reg {
|
||||||
data from the EEPROM or the write data
|
data from the EEPROM or the write data
|
||||||
to be written to the EEPROM.
|
to be written to the EEPROM.
|
||||||
===============================================*/
|
===============================================*/
|
||||||
|
#define EE_DATA (REGISTERS_BASE + 0x2004)
|
||||||
#define ACX_EE_DATA_REG EE_DATA
|
#define ACX_EE_DATA_REG EE_DATA
|
||||||
|
|
||||||
|
#define EEPROM_ACCESS_TO 10000 /* timeout counter */
|
||||||
|
#define START_EEPROM_MGR 0x00000001
|
||||||
|
|
||||||
/*===============================================
|
/*===============================================
|
||||||
EEPROM Base Address - 32bit RW
|
EEPROM Base Address - 32bit RW
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
|
@ -72,10 +72,6 @@ static void wl1251_rx_status(struct wl1251 *wl,
|
||||||
}
|
}
|
||||||
|
|
||||||
status->signal = desc->rssi;
|
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
|
* 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;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wl->use_eeprom = pdata->use_eeprom;
|
||||||
|
|
||||||
ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
|
ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
wl1251_error("request_irq() failed: %d", ret);
|
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)
|
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));
|
wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp));
|
||||||
return tmp & 0x80;
|
return tmp & 0x80;
|
||||||
|
|
|
@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev)
|
||||||
put_device(dev->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)
|
static int ssb_device_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct ssb_device *ssb_dev = dev_to_ssb_dev(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);
|
EXPORT_SYMBOL(ssb_bus_suspend);
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SPROM
|
#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_device *sdev;
|
||||||
struct ssb_driver *drv;
|
struct ssb_driver *sdrv;
|
||||||
int err = 0;
|
unsigned int i;
|
||||||
int i;
|
|
||||||
pm_message_t state = PMSG_FREEZE;
|
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++) {
|
for (i = 0; i < bus->nr_devices; i++) {
|
||||||
dev = &(bus->devices[i]);
|
sdev = ssb_device_get(&bus->devices[i]);
|
||||||
if (!dev->dev ||
|
|
||||||
!dev->dev->driver ||
|
if (!sdev->dev || !sdev->dev->driver ||
|
||||||
!device_is_registered(dev->dev))
|
!device_is_registered(sdev->dev)) {
|
||||||
|
ssb_device_put(sdev);
|
||||||
continue;
|
continue;
|
||||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
|
||||||
if (!drv)
|
|
||||||
continue;
|
|
||||||
if (!drv->suspend) {
|
|
||||||
/* Nope, can't suspend this one. */
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
}
|
||||||
}
|
sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
|
||||||
/* Now suspend all devices */
|
if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
|
||||||
for (i = 0; i < bus->nr_devices; i++) {
|
ssb_device_put(sdev);
|
||||||
dev = &(bus->devices[i]);
|
|
||||||
if (!dev->dev ||
|
|
||||||
!dev->dev->driver ||
|
|
||||||
!device_is_registered(dev->dev))
|
|
||||||
continue;
|
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;
|
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_bus *bus = ctx->bus;
|
||||||
struct ssb_driver *drv;
|
struct ssb_device *sdev;
|
||||||
int err;
|
struct ssb_driver *sdrv;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
int err, result = 0;
|
||||||
|
|
||||||
for (i = 0; i < bus->nr_devices; i++) {
|
for (i = 0; i < bus->nr_devices; i++) {
|
||||||
dev = &(bus->devices[i]);
|
if (!ctx->device_frozen[i])
|
||||||
if (!dev->dev ||
|
|
||||||
!dev->dev->driver ||
|
|
||||||
!device_is_registered(dev->dev))
|
|
||||||
continue;
|
continue;
|
||||||
drv = drv_to_ssb_drv(dev->dev->driver);
|
sdev = &bus->devices[i];
|
||||||
if (!drv)
|
|
||||||
|
if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver))
|
||||||
continue;
|
continue;
|
||||||
if (SSB_WARN_ON(!drv->resume))
|
sdrv = drv_to_ssb_drv(sdev->dev->driver);
|
||||||
|
if (SSB_WARN_ON(!sdrv || !sdrv->probe))
|
||||||
continue;
|
continue;
|
||||||
err = drv->resume(dev);
|
|
||||||
|
err = sdrv->probe(sdev, &sdev->id);
|
||||||
if (err) {
|
if (err) {
|
||||||
ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
|
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 */
|
#endif /* CONFIG_SSB_SPROM */
|
||||||
|
|
||||||
|
|
|
@ -354,7 +354,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
|
||||||
dev->bus = bus;
|
dev->bus = bus;
|
||||||
dev->ops = bus->ops;
|
dev->ops = bus->ops;
|
||||||
|
|
||||||
ssb_dprintk(KERN_INFO PFX
|
printk(KERN_DEBUG PFX
|
||||||
"Core %d found: %s "
|
"Core %d found: %s "
|
||||||
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
|
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
|
||||||
i, ssb_core_name(dev->id.coreid),
|
i, ssb_core_name(dev->id.coreid),
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include "ssb_private.h"
|
#include "ssb_private.h"
|
||||||
|
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
|
|
||||||
static const struct ssb_sprom *fallback_sprom;
|
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,
|
static int hex2sprom(u16 *sprom, const char *dump, size_t len,
|
||||||
size_t sprom_size_words)
|
size_t sprom_size_words)
|
||||||
{
|
{
|
||||||
char tmp[5] = { 0 };
|
char c, tmp[5] = { 0 };
|
||||||
int cnt = 0;
|
int err, cnt = 0;
|
||||||
unsigned long parsed;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
while (cnt < sprom_size_words) {
|
while (cnt < sprom_size_words) {
|
||||||
memcpy(tmp, dump, 4);
|
memcpy(tmp, dump, 4);
|
||||||
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);
|
sprom[cnt++] = swab16((u16)parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +102,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
|
||||||
u16 *sprom;
|
u16 *sprom;
|
||||||
int res = 0, err = -ENOMEM;
|
int res = 0, err = -ENOMEM;
|
||||||
size_t sprom_size_words = bus->sprom_size;
|
size_t sprom_size_words = bus->sprom_size;
|
||||||
|
struct ssb_freeze_context freeze;
|
||||||
|
|
||||||
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
|
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
|
||||||
if (!sprom)
|
if (!sprom)
|
||||||
|
@ -111,18 +124,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
|
||||||
err = -ERESTARTSYS;
|
err = -ERESTARTSYS;
|
||||||
if (mutex_lock_interruptible(&bus->sprom_mutex))
|
if (mutex_lock_interruptible(&bus->sprom_mutex))
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
err = ssb_devices_freeze(bus);
|
err = ssb_devices_freeze(bus, &freeze);
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (err) {
|
if (err) {
|
||||||
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
|
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
res = sprom_write(bus, sprom);
|
res = sprom_write(bus, sprom);
|
||||||
err = ssb_devices_thaw(bus);
|
err = ssb_devices_thaw(&freeze);
|
||||||
if (err)
|
if (err)
|
||||||
ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
|
ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
|
|
@ -176,13 +176,21 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
|
||||||
|
|
||||||
/* core.c */
|
/* core.c */
|
||||||
extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
|
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);
|
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
|
||||||
int ssb_for_each_bus_call(unsigned long data,
|
int ssb_for_each_bus_call(unsigned long data,
|
||||||
int (*func)(struct ssb_bus *bus, 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);
|
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 */
|
/* b43_pci_bridge.c */
|
||||||
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
|
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
|
||||||
|
|
|
@ -115,7 +115,6 @@
|
||||||
#define IEEE80211_MAX_SSID_LEN 32
|
#define IEEE80211_MAX_SSID_LEN 32
|
||||||
|
|
||||||
#define IEEE80211_MAX_MESH_ID_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_LEN 2
|
||||||
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
|
#define IEEE80211_QOS_CTL_TID_MASK 0x000F
|
||||||
|
@ -554,6 +553,21 @@ struct ieee80211_tim_ie {
|
||||||
u8 virtual_map[1];
|
u8 virtual_map[1];
|
||||||
} __attribute__ ((packed));
|
} __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
|
* struct ieee80211_rann_ie
|
||||||
*
|
*
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
|
#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
|
||||||
* release skb->dst
|
* release skb->dst
|
||||||
*/
|
*/
|
||||||
|
#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
|
||||||
|
|
||||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||||
#define IF_GET_PROTO 0x0002
|
#define IF_GET_PROTO 0x0002
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
* @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
|
* @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
|
||||||
* @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
|
* @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
|
||||||
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN 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
|
* @NUM_RFKILL_TYPES: number of defined rfkill types
|
||||||
*/
|
*/
|
||||||
enum rfkill_type {
|
enum rfkill_type {
|
||||||
|
@ -45,6 +47,7 @@ enum rfkill_type {
|
||||||
RFKILL_TYPE_WIMAX,
|
RFKILL_TYPE_WIMAX,
|
||||||
RFKILL_TYPE_WWAN,
|
RFKILL_TYPE_WWAN,
|
||||||
RFKILL_TYPE_GPS,
|
RFKILL_TYPE_GPS,
|
||||||
|
RFKILL_TYPE_FM,
|
||||||
NUM_RFKILL_TYPES,
|
NUM_RFKILL_TYPES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
struct wl12xx_platform_data {
|
struct wl12xx_platform_data {
|
||||||
void (*set_power)(bool enable);
|
void (*set_power)(bool enable);
|
||||||
|
bool use_eeprom;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1108,27 +1108,50 @@ struct cfg80211_ops {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct wiphy - wireless hardware description
|
* enum wiphy_flags - wiphy capability flags
|
||||||
* @idx: the wiphy index assigned to this item
|
*
|
||||||
* @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
|
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
|
||||||
* @custom_regulatory: tells us the driver for this device
|
|
||||||
* has its own custom regulatory domain and cannot identify the
|
* has its own custom regulatory domain and cannot identify the
|
||||||
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
|
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
|
||||||
* we will disregard the first regulatory hint (when the
|
* we will disregard the first regulatory hint (when the
|
||||||
* initiator is %REGDOM_SET_BY_CORE).
|
* initiator is %REGDOM_SET_BY_CORE).
|
||||||
* @strict_regulatory: tells us the driver for this device will ignore
|
* @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
|
||||||
* regulatory domain settings until it gets its own regulatory domain
|
* ignore regulatory domain settings until it gets its own regulatory
|
||||||
* via its regulatory_hint(). After its gets its own regulatory domain
|
* domain via its regulatory_hint(). After its gets its own regulatory
|
||||||
* it will only allow further regulatory domain settings to further
|
* domain it will only allow further regulatory domain settings to
|
||||||
* enhance compliance. For example if channel 13 and 14 are disabled
|
* further enhance compliance. For example if channel 13 and 14 are
|
||||||
* by this regulatory domain no user regulatory domain can enable these
|
* disabled by this regulatory domain no user regulatory domain can
|
||||||
* channels at a later time. This can be used for devices which do not
|
* enable these channels at a later time. This can be used for devices
|
||||||
* have calibration information gauranteed for frequencies or settings
|
* which do not have calibration information gauranteed for frequencies
|
||||||
* outside of its regulatory domain.
|
* or settings outside of its regulatory domain.
|
||||||
* @disable_beacon_hints: enable this if your driver needs to ensure that
|
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
|
||||||
* passive scan flags and beaconing flags may not be lifted by cfg80211
|
* that passive scan flags and beaconing flags may not be lifted by
|
||||||
* due to regulatory beacon hints. For more information on beacon
|
* cfg80211 due to regulatory beacon hints. For more information on beacon
|
||||||
* hints read the documenation for regulatory_hint_found_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
|
* @reg_notifier: the driver's regulatory notification callback
|
||||||
* @regd: the driver's regulatory domain, if one was requested via
|
* @regd: the driver's regulatory domain, if one was requested via
|
||||||
* the regulatory_hint() API. This can be used by the driver
|
* 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
|
* -1 = fragmentation disabled, only odd values >= 256 used
|
||||||
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
|
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
|
||||||
* @net: the network namespace this wiphy currently lives in
|
* @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 {
|
struct wiphy {
|
||||||
/* assign these fields before you register the wiphy */
|
/* assign these fields before you register the wiphy */
|
||||||
|
@ -1158,12 +1176,7 @@ struct wiphy {
|
||||||
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
|
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
|
||||||
u16 interface_modes;
|
u16 interface_modes;
|
||||||
|
|
||||||
bool custom_regulatory;
|
u32 flags;
|
||||||
bool strict_regulatory;
|
|
||||||
bool disable_beacon_hints;
|
|
||||||
|
|
||||||
bool netnsok;
|
|
||||||
bool ps_default;
|
|
||||||
|
|
||||||
enum cfg80211_signal_type signal_type;
|
enum cfg80211_signal_type signal_type;
|
||||||
|
|
||||||
|
@ -1358,6 +1371,10 @@ struct cfg80211_cached_keys;
|
||||||
* @ssid_len: (private) Used by the internal configuration code
|
* @ssid_len: (private) Used by the internal configuration code
|
||||||
* @wext: (private) Used by the internal wireless extensions compat code
|
* @wext: (private) Used by the internal wireless extensions compat code
|
||||||
* @wext_bssid: (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 wireless_dev {
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
|
@ -1371,6 +1388,8 @@ struct wireless_dev {
|
||||||
|
|
||||||
struct work_struct cleanup_work;
|
struct work_struct cleanup_work;
|
||||||
|
|
||||||
|
bool use_4addr;
|
||||||
|
|
||||||
/* currently used for IBSS and SME - might be rearranged later */
|
/* currently used for IBSS and SME - might be rearranged later */
|
||||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||||
u8 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);
|
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
|
* cfg80211_send_rx_assoc - notification of processed association
|
||||||
* @dev: network device
|
* @dev: network device
|
||||||
|
|
|
@ -219,7 +219,7 @@ struct ieee80211_bss_conf {
|
||||||
*
|
*
|
||||||
* These flags are used with the @flags member of &ieee80211_tx_info.
|
* 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
|
* @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
|
||||||
* number to this frame, taking care of not overwriting the fragment
|
* number to this frame, taking care of not overwriting the fragment
|
||||||
* number and increasing the sequence number only when the
|
* number and increasing the sequence number only when the
|
||||||
|
@ -390,10 +390,12 @@ struct ieee80211_tx_rate {
|
||||||
* @control: union for control data
|
* @control: union for control data
|
||||||
* @status: union for status data
|
* @status: union for status data
|
||||||
* @driver_data: array of driver_data pointers
|
* @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.
|
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
||||||
* @ampdu_ack_map: block ack bit map for the aggregation.
|
* @ampdu_ack_map: block ack bit map for the aggregation.
|
||||||
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
* 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
|
* @ack_signal: signal strength of the ACK frame
|
||||||
*/
|
*/
|
||||||
struct ieee80211_tx_info {
|
struct ieee80211_tx_info {
|
||||||
|
@ -428,7 +430,8 @@ struct ieee80211_tx_info {
|
||||||
u8 ampdu_ack_len;
|
u8 ampdu_ack_len;
|
||||||
u64 ampdu_ack_map;
|
u64 ampdu_ack_map;
|
||||||
int ack_signal;
|
int ack_signal;
|
||||||
/* 8 bytes free */
|
u8 ampdu_len;
|
||||||
|
/* 7 bytes free */
|
||||||
} status;
|
} status;
|
||||||
struct {
|
struct {
|
||||||
struct ieee80211_tx_rate driver_rates[
|
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,
|
* any particular flags. There are some exceptions to this rule,
|
||||||
* however, so you are advised to review these flags carefully.
|
* 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:
|
* @IEEE80211_HW_RX_INCLUDES_FCS:
|
||||||
* Indicates that received frames passed to the stack include
|
* Indicates that received frames passed to the stack include
|
||||||
* the FCS at the end.
|
* the FCS at the end.
|
||||||
|
@ -910,6 +926,7 @@ enum ieee80211_tkip_key_type {
|
||||||
* avoid waking up cpu.
|
* avoid waking up cpu.
|
||||||
*/
|
*/
|
||||||
enum ieee80211_hw_flags {
|
enum ieee80211_hw_flags {
|
||||||
|
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||||||
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
|
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
|
||||||
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
|
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
|
||||||
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
|
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
|
||||||
|
@ -1505,6 +1522,7 @@ struct ieee80211_ops {
|
||||||
void (*reset_tsf)(struct ieee80211_hw *hw);
|
void (*reset_tsf)(struct ieee80211_hw *hw);
|
||||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
|
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.
|
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
|
||||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
* @sta: the station for which to start a BA session
|
||||||
* @ra: receiver address of the BA session recipient
|
|
||||||
* @tid: the TID to BA on.
|
* @tid: the TID to BA on.
|
||||||
*
|
*
|
||||||
* Return: success if addBA request was sent, failure otherwise
|
* 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
|
* the need to start aggregation on a certain RA/TID, the session level
|
||||||
* will be managed by the mac80211.
|
* 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.
|
* 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.
|
* @ra: receiver address of the BA session recipient.
|
||||||
* @tid: the TID to BA on.
|
* @tid: the TID to BA on.
|
||||||
*
|
*
|
||||||
* This function must be called by low level driver once it has
|
* This function must be called by low level driver once it has
|
||||||
* finished with preparations for the BA session.
|
* 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.
|
* 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.
|
* @ra: receiver address of the BA session recipient.
|
||||||
* @tid: the TID to BA on.
|
* @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.
|
* finished with preparations for the BA session.
|
||||||
* This version of the function is IRQ-safe.
|
* 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);
|
u16 tid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
|
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
|
||||||
* @hw: pointer as obtained from ieee80211_alloc_hw().
|
* @sta: the station whose BA session to stop
|
||||||
* @ra: receiver address of the BA session recipient
|
|
||||||
* @tid: the TID to stop BA.
|
* @tid: the TID to stop BA.
|
||||||
* @initiator: if indicates initiator DELBA frame will be sent.
|
* @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
|
* the need to stop aggregation on a certain RA/TID, the session level
|
||||||
* will be managed by the mac80211.
|
* will be managed by the mac80211.
|
||||||
*/
|
*/
|
||||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
|
||||||
u8 *ra, u16 tid,
|
|
||||||
enum ieee80211_back_parties initiator);
|
enum ieee80211_back_parties initiator);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
|
* 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.
|
* @ra: receiver address of the BA session recipient.
|
||||||
* @tid: the desired TID to BA on.
|
* @tid: the desired TID to BA on.
|
||||||
*
|
*
|
||||||
* This function must be called by low level driver once it has
|
* This function must be called by low level driver once it has
|
||||||
* finished with preparations for the BA session tear down.
|
* 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.
|
* 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.
|
* @ra: receiver address of the BA session recipient.
|
||||||
* @tid: the desired TID to BA on.
|
* @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.
|
* finished with preparations for the BA session tear down.
|
||||||
* This version of the function is IRQ-safe.
|
* 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);
|
u16 tid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -390,6 +390,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
||||||
if (dev->br_port != NULL)
|
if (dev->br_port != NULL)
|
||||||
return -EBUSY;
|
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);
|
p = new_nbp(br, dev);
|
||||||
if (IS_ERR(p))
|
if (IS_ERR(p))
|
||||||
return PTR_ERR(p);
|
return PTR_ERR(p);
|
||||||
|
|
|
@ -2,7 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o
|
||||||
|
|
||||||
# mac80211 objects
|
# mac80211 objects
|
||||||
mac80211-y := \
|
mac80211-y := \
|
||||||
main.o \
|
main.o status.o \
|
||||||
sta_info.o \
|
sta_info.o \
|
||||||
wep.o \
|
wep.o \
|
||||||
wpa.o \
|
wpa.o \
|
||||||
|
|
|
@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
#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))
|
&sta->sta, tid, NULL))
|
||||||
printk(KERN_DEBUG "HW problem - can not stop rx "
|
printk(KERN_DEBUG "HW problem - can not stop rx "
|
||||||
"aggregation for tid %d\n", tid);
|
"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.timeout = cpu_to_le16(timeout);
|
||||||
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
|
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,
|
void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||||
|
@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||||
goto end;
|
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);
|
&sta->sta, tid, &start_seq_num);
|
||||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||||
printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
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 =
|
mgmt->u.action.u.addba_req.start_seq_num =
|
||||||
cpu_to_le16(start_seq_num << 4);
|
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)
|
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->control = cpu_to_le16(bar_control);
|
||||||
bar->start_seq_num = cpu_to_le16(ssn);
|
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,
|
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 |
|
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
|
||||||
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
|
(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);
|
&sta->sta, tid, NULL);
|
||||||
|
|
||||||
/* HW shall not deny going back to legacy */
|
/* 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];
|
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 = container_of(pubsta, struct sta_info, sta);
|
||||||
struct sta_info *sta;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_local *local = sdata->local;
|
||||||
u8 *state;
|
u8 *state;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u16 start_seq_num;
|
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))
|
if (WARN_ON(!local->ops->ampdu_action))
|
||||||
return -EINVAL;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||||
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
|
||||||
ra, tid);
|
pubsta->addr, tid);
|
||||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
#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
|
* The aggregation code is not prepared to handle
|
||||||
* anything but STA/AP due to the BSSID handling.
|
* anything but STA/AP due to the BSSID handling.
|
||||||
* IBSS could work in the code but isn't supported
|
* IBSS could work in the code but isn't supported
|
||||||
* by drivers or the standard.
|
* by drivers or the standard.
|
||||||
*/
|
*/
|
||||||
if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
|
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||||
sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||||
sta->sdata->vif.type != NL80211_IFTYPE_AP) {
|
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
|
if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
|
||||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||||
printk(KERN_DEBUG "Suspend in progress. "
|
printk(KERN_DEBUG "Suspend in progress. "
|
||||||
"Denying BA session request\n");
|
"Denying BA session request\n");
|
||||||
#endif
|
#endif
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_bh(&sta->lock);
|
spin_lock_bh(&sta->lock);
|
||||||
spin_lock(&local->ampdu_lock);
|
spin_lock(&local->ampdu_lock);
|
||||||
|
|
||||||
sdata = sta->sdata;
|
|
||||||
|
|
||||||
/* we have tried too many times, receiver does not want A-MPDU */
|
/* we have tried too many times, receiver does not want A-MPDU */
|
||||||
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
|
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
|
||||||
ret = -EBUSY;
|
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];
|
start_seq_num = sta->tid_seq[tid];
|
||||||
|
|
||||||
ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
|
ret = drv_ampdu_action(local, &sdata->vif,
|
||||||
&sta->sta, tid, &start_seq_num);
|
IEEE80211_AMPDU_TX_START,
|
||||||
|
pubsta, tid, &start_seq_num);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
#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.dialog_token_allocator;
|
||||||
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
|
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]->dialog_token,
|
||||||
sta->ampdu_mlme.tid_tx[tid]->ssn,
|
sta->ampdu_mlme.tid_tx[tid]->ssn,
|
||||||
0x40, 5000);
|
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
|
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||||
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
|
||||||
#endif
|
#endif
|
||||||
goto unlock;
|
return 0;
|
||||||
|
|
||||||
err_free:
|
err_free:
|
||||||
kfree(sta->ampdu_mlme.tid_tx[tid]);
|
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:
|
err_unlock_sta:
|
||||||
spin_unlock(&local->ampdu_lock);
|
spin_unlock(&local->ampdu_lock);
|
||||||
spin_unlock_bh(&sta->lock);
|
spin_unlock_bh(&sta->lock);
|
||||||
unlock:
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
|
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);
|
ieee80211_agg_splice_finish(local, sta, tid);
|
||||||
spin_unlock(&local->ampdu_lock);
|
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);
|
&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;
|
struct sta_info *sta;
|
||||||
u8 *state;
|
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);
|
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)
|
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 ieee80211_ra_tid *ra_tid;
|
||||||
struct sk_buff *skb = dev_alloc_skb(0);
|
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;
|
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||||
ra_tid->tid = tid;
|
ra_tid->tid = tid;
|
||||||
|
ra_tid->vif = vif;
|
||||||
|
|
||||||
skb->pkt_type = IEEE80211_ADDBA_MSG;
|
skb->pkt_type = IEEE80211_ADDBA_MSG;
|
||||||
skb_queue_tail(&local->skb_queue, skb);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||||
u8 *ra, u16 tid,
|
|
||||||
enum ieee80211_back_parties initiator)
|
enum ieee80211_back_parties initiator)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = hw_to_local(hw);
|
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||||
struct sta_info *sta;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
int ret = 0;
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
|
||||||
if (WARN_ON(!local->ops->ampdu_action))
|
if (WARN_ON(!local->ops->ampdu_action))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -549,22 +538,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
|
||||||
if (tid >= STA_TID_NUM)
|
if (tid >= STA_TID_NUM)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rcu_read_lock();
|
return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
|
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;
|
struct sta_info *sta;
|
||||||
u8 *state;
|
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);
|
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)
|
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 ieee80211_ra_tid *ra_tid;
|
||||||
struct sk_buff *skb = dev_alloc_skb(0);
|
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;
|
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||||
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
memcpy(&ra_tid->ra, ra, ETH_ALEN);
|
||||||
ra_tid->tid = tid;
|
ra_tid->tid = tid;
|
||||||
|
ra_tid->vif = vif;
|
||||||
|
|
||||||
skb->pkt_type = IEEE80211_DELBA_MSG;
|
skb->pkt_type = IEEE80211_DELBA_MSG;
|
||||||
skb_queue_tail(&local->skb_queue, skb);
|
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))
|
if (!nl80211_type_check(type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (params->use_4addr > 0) {
|
|
||||||
switch(type) {
|
|
||||||
case NL80211_IFTYPE_AP_VLAN:
|
|
||||||
case NL80211_IFTYPE_STATION:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
||||||
params->mesh_id_len,
|
params->mesh_id_len,
|
||||||
params->mesh_id);
|
params->mesh_id);
|
||||||
|
|
||||||
if (params->use_4addr >= 0)
|
|
||||||
sdata->use_4addr = !!params->use_4addr;
|
|
||||||
|
|
||||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
|
if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
|
||||||
return 0;
|
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;
|
sdata->u.mntr_flags = *flags;
|
||||||
return 0;
|
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,
|
static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
||||||
int idx, u8 *mac, struct station_info *sinfo)
|
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;
|
struct sta_info *sta;
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
sta = sta_info_get_by_idx(local, idx, dev);
|
sta = sta_info_get_by_idx(sdata, idx);
|
||||||
if (sta) {
|
if (sta) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
memcpy(mac, sta->sta.addr, ETH_ALEN);
|
memcpy(mac, sta->sta.addr, ETH_ALEN);
|
||||||
|
@ -827,9 +822,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlansdata->use_4addr) {
|
if (params->vlan->ieee80211_ptr->use_4addr) {
|
||||||
if (vlansdata->u.vlan.sta)
|
if (vlansdata->u.vlan.sta) {
|
||||||
|
rcu_read_unlock();
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
|
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",
|
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
|
||||||
local->wep_iv & 0xffffff);
|
local->wep_iv & 0xffffff);
|
||||||
DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
|
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,
|
static ssize_t tsf_read(struct file *file, char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
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);
|
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) \
|
#define DEBUGFS_ADD(name) \
|
||||||
debugfs_create_file(#name, 0400, \
|
debugfs_create_file(#name, 0400, \
|
||||||
sta->debugfs.dir, sta, &sta_ ##name## _ops);
|
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_signal);
|
||||||
DEBUGFS_ADD(last_noise);
|
DEBUGFS_ADD(last_noise);
|
||||||
DEBUGFS_ADD(wep_weak_iv_count);
|
DEBUGFS_ADD(wep_weak_iv_count);
|
||||||
|
DEBUGFS_ADD(ht_capa);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
|
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,
|
static inline int drv_ampdu_action(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
struct ieee80211_sta *sta, u16 tid,
|
||||||
u16 *ssn)
|
u16 *ssn)
|
||||||
{
|
{
|
||||||
int ret = -EOPNOTSUPP;
|
int ret = -EOPNOTSUPP;
|
||||||
if (local->ops->ampdu_action)
|
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);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon,
|
||||||
|
|
||||||
TRACE_EVENT(drv_ampdu_action,
|
TRACE_EVENT(drv_ampdu_action,
|
||||||
TP_PROTO(struct ieee80211_local *local,
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
enum ieee80211_ampdu_mlme_action action,
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
struct ieee80211_sta *sta, u16 tid,
|
||||||
u16 *ssn, int ret),
|
u16 *ssn, int ret),
|
||||||
|
|
||||||
TP_ARGS(local, action, sta, tid, ssn, ret),
|
TP_ARGS(local, vif, action, sta, tid, ssn, ret),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
LOCAL_ENTRY
|
LOCAL_ENTRY
|
||||||
|
@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action,
|
||||||
__field(u16, tid)
|
__field(u16, tid)
|
||||||
__field(u16, ssn)
|
__field(u16, ssn)
|
||||||
__field(int, ret)
|
__field(int, ret)
|
||||||
|
VIF_ENTRY
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
LOCAL_ASSIGN;
|
LOCAL_ASSIGN;
|
||||||
|
VIF_ASSIGN;
|
||||||
STA_ASSIGN;
|
STA_ASSIGN;
|
||||||
__entry->ret = ret;
|
__entry->ret = ret;
|
||||||
__entry->action = action;
|
__entry->action = action;
|
||||||
|
@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action,
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
|
LOCAL_PR_FMT VIF_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_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
#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.params = cpu_to_le16(params);
|
||||||
mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
|
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,
|
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
struct ieee80211_mgmt *mgmt, size_t len)
|
struct ieee80211_mgmt *mgmt, size_t len)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
|
||||||
u16 tid, params;
|
u16 tid, params;
|
||||||
u16 initiator;
|
u16 initiator;
|
||||||
|
|
||||||
|
@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||||
sta->ampdu_mlme.tid_state_tx[tid] =
|
sta->ampdu_mlme.tid_state_tx[tid] =
|
||||||
HT_AGG_STATE_OPERATIONAL;
|
HT_AGG_STATE_OPERATIONAL;
|
||||||
spin_unlock_bh(&sta->lock);
|
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);
|
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",
|
printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
|
||||||
sdata->dev->name, resp->da);
|
sdata->dev->name, resp->da);
|
||||||
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
|
#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,
|
static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
|
#include <net/ieee80211_radiotap.h>
|
||||||
#include <net/cfg80211.h>
|
#include <net/cfg80211.h>
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
@ -167,13 +168,10 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
||||||
|
|
||||||
struct ieee80211_rx_data {
|
struct ieee80211_rx_data {
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct net_device *dev;
|
|
||||||
struct ieee80211_local *local;
|
struct ieee80211_local *local;
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
struct ieee80211_key *key;
|
struct ieee80211_key *key;
|
||||||
struct ieee80211_rx_status *status;
|
|
||||||
struct ieee80211_rate *rate;
|
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
int queue;
|
int queue;
|
||||||
|
@ -314,6 +312,8 @@ struct ieee80211_if_managed {
|
||||||
} mfp; /* management frame protection */
|
} mfp; /* management frame protection */
|
||||||
|
|
||||||
int wmm_last_param_set;
|
int wmm_last_param_set;
|
||||||
|
|
||||||
|
u8 use_4addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ieee80211_ibss_request {
|
enum ieee80211_ibss_request {
|
||||||
|
@ -461,8 +461,6 @@ struct ieee80211_sub_if_data {
|
||||||
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
|
||||||
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
|
||||||
|
|
||||||
bool use_4addr; /* use 4-address frames */
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct ieee80211_if_ap ap;
|
struct ieee80211_if_ap ap;
|
||||||
struct ieee80211_if_wds wds;
|
struct ieee80211_if_wds wds;
|
||||||
|
@ -581,7 +579,6 @@ struct ieee80211_local {
|
||||||
/* number of interfaces with corresponding FIF_ flags */
|
/* number of interfaces with corresponding FIF_ flags */
|
||||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
|
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
|
||||||
unsigned int filter_flags; /* FIF_* */
|
unsigned int filter_flags; /* FIF_* */
|
||||||
struct iw_statistics wstats;
|
|
||||||
|
|
||||||
/* protects the aggregated multicast list and filter calls */
|
/* protects the aggregated multicast list and filter calls */
|
||||||
spinlock_t filter_lock;
|
spinlock_t filter_lock;
|
||||||
|
@ -771,8 +768,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
|
||||||
return netdev_priv(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_ra_tid {
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
u8 ra[ETH_ALEN];
|
u8 ra[ETH_ALEN];
|
||||||
u16 tid;
|
u16 tid;
|
||||||
};
|
};
|
||||||
|
@ -799,7 +797,7 @@ struct ieee802_11_elems {
|
||||||
u8 *wmm_param;
|
u8 *wmm_param;
|
||||||
struct ieee80211_ht_cap *ht_cap_elem;
|
struct ieee80211_ht_cap *ht_cap_elem;
|
||||||
struct ieee80211_ht_info *ht_info_elem;
|
struct ieee80211_ht_info *ht_info_elem;
|
||||||
u8 *mesh_config;
|
struct ieee80211_meshconf_ie *mesh_config;
|
||||||
u8 *mesh_id;
|
u8 *mesh_id;
|
||||||
u8 *peer_link;
|
u8 *peer_link;
|
||||||
u8 *preq;
|
u8 *preq;
|
||||||
|
@ -827,7 +825,6 @@ struct ieee802_11_elems {
|
||||||
u8 ext_supp_rates_len;
|
u8 ext_supp_rates_len;
|
||||||
u8 wmm_info_len;
|
u8 wmm_info_len;
|
||||||
u8 wmm_param_len;
|
u8 wmm_param_len;
|
||||||
u8 mesh_config_len;
|
|
||||||
u8 mesh_id_len;
|
u8 mesh_id_len;
|
||||||
u8 peer_link_len;
|
u8 peer_link_len;
|
||||||
u8 preq_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,
|
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||||
struct net_device *dev);
|
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 */
|
/* HT */
|
||||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||||
struct ieee80211_ht_cap *ht_cap_ie,
|
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,
|
struct ieee80211_hdr *hdr, const u8 *tsc,
|
||||||
gfp_t gfp);
|
gfp_t gfp);
|
||||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
|
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,
|
void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
|
||||||
int encrypt);
|
|
||||||
void ieee802_11_parse_elems(u8 *start, size_t len,
|
void ieee802_11_parse_elems(u8 *start, size_t len,
|
||||||
struct ieee802_11_elems *elems);
|
struct ieee802_11_elems *elems);
|
||||||
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
|
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,
|
ieee80211_mandatory_rates(sdata->local,
|
||||||
sdata->local->hw.conf.channel->band);
|
sdata->local->hw.conf.channel->band);
|
||||||
sdata->drop_unencrypted = 0;
|
sdata->drop_unencrypted = 0;
|
||||||
sdata->use_4addr = 0;
|
if (type == NL80211_IFTYPE_STATION)
|
||||||
|
sdata->u.mgd.use_4addr = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||||
/* setup type-dependent data */
|
/* setup type-dependent data */
|
||||||
ieee80211_setup_sdata(sdata, type);
|
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);
|
ret = register_netdevice(ndev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||||
params->mesh_id_len,
|
params->mesh_id_len,
|
||||||
params->mesh_id);
|
params->mesh_id);
|
||||||
|
|
||||||
if (params && params->use_4addr >= 0)
|
|
||||||
sdata->use_4addr = !!params->use_4addr;
|
|
||||||
|
|
||||||
mutex_lock(&local->iflist_mtx);
|
mutex_lock(&local->iflist_mtx);
|
||||||
list_add_tail_rcu(&sdata->list, &local->interfaces);
|
list_add_tail_rcu(&sdata->list, &local->interfaces);
|
||||||
mutex_unlock(&local->iflist_mtx);
|
mutex_unlock(&local->iflist_mtx);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
#include <net/ieee80211_radiotap.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
@ -30,26 +29,11 @@
|
||||||
#include "rate.h"
|
#include "rate.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
#include "wep.h"
|
#include "wep.h"
|
||||||
#include "wme.h"
|
|
||||||
#include "aes_ccm.h"
|
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "debugfs.h"
|
#include "debugfs.h"
|
||||||
#include "debugfs_netdev.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)
|
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||||
{
|
{
|
||||||
u64 mc;
|
u64 mc;
|
||||||
|
@ -253,28 +237,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
|
||||||
BSS_CHANGED_ERP_SLOT;
|
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)
|
static void ieee80211_tasklet_handler(unsigned long data)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = (struct ieee80211_local *) data;
|
struct ieee80211_local *local = (struct ieee80211_local *) data;
|
||||||
|
@ -296,14 +258,14 @@ static void ieee80211_tasklet_handler(unsigned long data)
|
||||||
break;
|
break;
|
||||||
case IEEE80211_DELBA_MSG:
|
case IEEE80211_DELBA_MSG:
|
||||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||||
ieee80211_stop_tx_ba_cb(local_to_hw(local),
|
ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
|
||||||
ra_tid->ra, ra_tid->tid);
|
ra_tid->tid);
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
case IEEE80211_ADDBA_MSG:
|
case IEEE80211_ADDBA_MSG:
|
||||||
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
|
||||||
ieee80211_start_tx_ba_cb(local_to_hw(local),
|
ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
|
||||||
ra_tid->ra, ra_tid->tid);
|
ra_tid->tid);
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
break ;
|
break ;
|
||||||
default:
|
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)
|
static void ieee80211_restart_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local =
|
struct ieee80211_local *local =
|
||||||
|
@ -659,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||||
if (!wiphy)
|
if (!wiphy)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
wiphy->netnsok = true;
|
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
|
||||||
|
WIPHY_FLAG_4ADDR_AP |
|
||||||
|
WIPHY_FLAG_4ADDR_STATION;
|
||||||
wiphy->privid = mac80211_wiphy_privid;
|
wiphy->privid = mac80211_wiphy_privid;
|
||||||
|
|
||||||
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
||||||
|
|
|
@ -16,12 +16,6 @@
|
||||||
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
||||||
#define IEEE80211_MESH_RANN_INTERVAL (1 * 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_ACCEPT_PLINKS 0x01
|
||||||
#define MESHCONF_CAPAB_FORWARDING 0x08
|
#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 &&
|
if (ifmsh->mesh_id_len == ie->mesh_id_len &&
|
||||||
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
|
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
|
||||||
(ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&&
|
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
|
||||||
(ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&&
|
(ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
|
||||||
(ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&&
|
(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
|
||||||
(ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&&
|
(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
|
||||||
(ifmsh->mesh_auth_id == *(ie->mesh_config +
|
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
|
||||||
MESHCONF_AUTH_OFFSET)))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
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)
|
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;
|
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)
|
if (sdata->u.mesh.mesh_id_len)
|
||||||
memcpy(pos, sdata->u.mesh.mesh_id, 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++ = WLAN_EID_MESH_CONFIG;
|
||||||
*pos++ = IEEE80211_MESH_CONFIG_LEN;
|
*pos++ = sizeof(struct ieee80211_meshconf_ie);
|
||||||
|
|
||||||
/* Active path selection protocol ID */
|
/* Active path selection protocol ID */
|
||||||
*pos++ = sdata->u.mesh.mesh_pp_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)
|
* 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
|
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||||
*meshda, char *meshsa) {
|
const u8 *meshda, const u8 *meshsa)
|
||||||
|
{
|
||||||
if (is_multicast_ether_addr(meshda)) {
|
if (is_multicast_ether_addr(meshda)) {
|
||||||
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||||
/* DA TA SA */
|
/* DA TA SA */
|
||||||
|
|
|
@ -220,7 +220,7 @@ struct mesh_rmc {
|
||||||
/* Public interfaces */
|
/* Public interfaces */
|
||||||
/* Various */
|
/* Various */
|
||||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
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,
|
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
|
||||||
struct ieee80211_sub_if_data *sdata, char *addr4,
|
struct ieee80211_sub_if_data *sdata, char *addr4,
|
||||||
char *addr5, char *addr6);
|
char *addr5, char *addr6);
|
||||||
|
@ -284,7 +284,7 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
|
||||||
struct mesh_table *tbl);
|
struct mesh_table *tbl);
|
||||||
/* Mesh paths */
|
/* Mesh paths */
|
||||||
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode,
|
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_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
|
||||||
void mesh_path_flush_pending(struct mesh_path *mpath);
|
void mesh_path_flush_pending(struct mesh_path *mpath);
|
||||||
void mesh_path_tx_pending(struct mesh_path *mpath);
|
void mesh_path_tx_pending(struct mesh_path *mpath);
|
||||||
|
|
|
@ -101,10 +101,12 @@ enum mpath_frame_type {
|
||||||
MPATH_RANN
|
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,
|
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,
|
u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
|
||||||
__le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime,
|
__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
|
||||||
__le32 metric, __le32 preq_id,
|
__le32 lifetime, __le32 metric, __le32 preq_id,
|
||||||
struct ieee80211_sub_if_data *sdata)
|
struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
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);
|
memcpy(pos, &target_sn, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
ieee80211_tx_skb(sdata, skb, 1);
|
ieee80211_tx_skb(sdata, skb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +200,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||||
* @ra: node this frame is addressed to
|
* @ra: node this frame is addressed to
|
||||||
*/
|
*/
|
||||||
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
||||||
__le16 target_rcode, u8 *ra,
|
__le16 target_rcode, const u8 *ra,
|
||||||
struct ieee80211_sub_if_data *sdata)
|
struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
@ -248,7 +250,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
||||||
pos += 4;
|
pos += 4;
|
||||||
memcpy(pos, &target_rcode, 2);
|
memcpy(pos, &target_rcode, 2);
|
||||||
|
|
||||||
ieee80211_tx_skb(sdata, skb, 1);
|
ieee80211_tx_skb(sdata, skb);
|
||||||
return 0;
|
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;
|
hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
|
||||||
mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
|
mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
|
||||||
cpu_to_le32(orig_sn), target_flags, target_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),
|
hopcount, ttl, cpu_to_le32(lifetime),
|
||||||
cpu_to_le32(metric), cpu_to_le32(preq_id),
|
cpu_to_le32(metric), cpu_to_le32(preq_id),
|
||||||
sdata);
|
sdata);
|
||||||
|
@ -660,7 +662,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
|
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
|
||||||
cpu_to_le16(target_rcode),
|
cpu_to_le16(target_rcode),
|
||||||
sdata->dev->broadcast, sdata);
|
broadcast_addr, sdata);
|
||||||
} else
|
} else
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
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) {
|
if (mpath->sn < orig_sn) {
|
||||||
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
|
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
|
||||||
cpu_to_le32(orig_sn),
|
cpu_to_le32(orig_sn),
|
||||||
0, NULL, 0, sdata->dev->broadcast,
|
0, NULL, 0, broadcast_addr,
|
||||||
hopcount, ttl, 0,
|
hopcount, ttl, 0,
|
||||||
cpu_to_le32(metric + mpath->metric),
|
cpu_to_le32(metric + mpath->metric),
|
||||||
0, sdata);
|
0, sdata);
|
||||||
|
@ -890,7 +892,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
|
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
|
||||||
cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
|
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,
|
ttl, cpu_to_le32(lifetime), 0,
|
||||||
cpu_to_le32(ifmsh->preq_id++), sdata);
|
cpu_to_le32(ifmsh->preq_id++), sdata);
|
||||||
mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
|
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,
|
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
|
||||||
cpu_to_le32(++ifmsh->sn),
|
cpu_to_le32(++ifmsh->sn),
|
||||||
0, NULL, 0, sdata->dev->broadcast,
|
0, NULL, 0, broadcast_addr,
|
||||||
0, MESH_TTL, 0, 0, 0, sdata);
|
0, MESH_TTL, 0, 0, 0, sdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,6 +449,7 @@ err_path_alloc:
|
||||||
*/
|
*/
|
||||||
void mesh_plink_broken(struct sta_info *sta)
|
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 mesh_path *mpath;
|
||||||
struct mpath_node *node;
|
struct mpath_node *node;
|
||||||
struct hlist_node *p;
|
struct hlist_node *p;
|
||||||
|
@ -467,8 +468,8 @@ void mesh_plink_broken(struct sta_info *sta)
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
mesh_path_error_tx(MESH_TTL, mpath->dst,
|
mesh_path_error_tx(MESH_TTL, mpath->dst,
|
||||||
cpu_to_le32(mpath->sn),
|
cpu_to_le32(mpath->sn),
|
||||||
PERR_RCODE_DEST_UNREACH,
|
cpu_to_le16(PERR_RCODE_DEST_UNREACH),
|
||||||
sdata->dev->broadcast, sdata);
|
bcast, sdata);
|
||||||
} else
|
} else
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
}
|
}
|
||||||
|
@ -613,7 +614,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
|
||||||
if (mpath)
|
if (mpath)
|
||||||
sn = ++mpath->sn;
|
sn = ++mpath->sn;
|
||||||
mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(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);
|
kfree_skb(skb);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue