mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
@@ -850,6 +850,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
|
||||
}
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
case AR9170_RX_STATUS_MODULATION_OFDM:
|
||||
switch (head->plcp[0] & 0xf) {
|
||||
case 0xb:
|
||||
@@ -897,8 +898,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
|
||||
status->flag |= RX_FLAG_HT;
|
||||
break;
|
||||
|
||||
case AR9170_RX_STATUS_MODULATION_DUPOFDM:
|
||||
/* XXX */
|
||||
default:
|
||||
if (ar9170_nag_limiter(ar))
|
||||
printk(KERN_ERR "%s: invalid modulation\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
@@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
}
|
||||
|
||||
static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
|
||||
{
|
||||
@@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
tid_info->state = AR9170_TID_STATE_PROGRESS;
|
||||
tid_info->active = false;
|
||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
@@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
|
||||
tid_info->active = false;
|
||||
skb_queue_purge(&tid_info->queue);
|
||||
spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
|
||||
@@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
||||
{ USB_DEVICE(0x0cf3, 0x1002) },
|
||||
/* Cace Airpcap NX */
|
||||
{ USB_DEVICE(0xcace, 0x0300) },
|
||||
/* D-Link DWA 160A */
|
||||
/* D-Link DWA 160 A1 */
|
||||
{ USB_DEVICE(0x07d1, 0x3c10) },
|
||||
/* D-Link DWA 160 A2 */
|
||||
{ USB_DEVICE(0x07d1, 0x3a09) },
|
||||
/* Netgear WNDA3100 */
|
||||
{ USB_DEVICE(0x0846, 0x9010) },
|
||||
/* Netgear WN111 v2 */
|
||||
|
||||
@@ -1399,7 +1399,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
||||
if (i_coffd == 0 || q_coffd == 0)
|
||||
goto done;
|
||||
|
||||
i_coff = ((-iq_corr) / i_coffd) & 0x3f;
|
||||
i_coff = ((-iq_corr) / i_coffd);
|
||||
|
||||
/* Boundary check */
|
||||
if (i_coff > 31)
|
||||
@@ -1407,7 +1407,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
|
||||
if (i_coff < -32)
|
||||
i_coff = -32;
|
||||
|
||||
q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
|
||||
q_coff = (((s32)i_pwr / q_coffd) - 128);
|
||||
|
||||
/* Boundary check */
|
||||
if (q_coff > 15)
|
||||
|
||||
@@ -198,18 +198,8 @@ struct ath_txq {
|
||||
struct list_head axq_q;
|
||||
spinlock_t axq_lock;
|
||||
u32 axq_depth;
|
||||
u8 axq_aggr_depth;
|
||||
bool stopped;
|
||||
bool axq_tx_inprogress;
|
||||
struct ath_buf *axq_linkbuf;
|
||||
|
||||
/* first desc of the last descriptor that contains CTS */
|
||||
struct ath_desc *axq_lastdsWithCTS;
|
||||
|
||||
/* final desc of the gating desc that determines whether
|
||||
lastdsWithCTS has been DMA'ed or not */
|
||||
struct ath_desc *axq_gatingds;
|
||||
|
||||
struct list_head axq_acq;
|
||||
};
|
||||
|
||||
|
||||
@@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int hdrlen, padsize;
|
||||
int hdrlen, padpos, padsize;
|
||||
u8 keyix;
|
||||
__le16 fc;
|
||||
|
||||
/* see if any padding is done by the hw and remove it */
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
padpos = 24;
|
||||
fc = hdr->frame_control;
|
||||
if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
|
||||
cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
|
||||
padpos += 6; /* ETH_ALEN */
|
||||
}
|
||||
if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
|
||||
cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
|
||||
padpos += 2;
|
||||
}
|
||||
|
||||
/* The MAC header is padded to have 32-bit boundary if the
|
||||
* packet payload is non-zero. The general calculation for
|
||||
* padsize would take into account odd header lengths:
|
||||
* padsize = (4 - hdrlen % 4) % 4; However, since only
|
||||
* padsize = (4 - padpos % 4) % 4; However, since only
|
||||
* even-length headers are used, padding can only be 0 or 2
|
||||
* bytes and we can optimize this a bit. In addition, we must
|
||||
* not try to remove padding from short control frames that do
|
||||
* not have payload. */
|
||||
padsize = hdrlen & 3;
|
||||
if (padsize && hdrlen >= 24) {
|
||||
memmove(skb->data + padsize, skb->data, hdrlen);
|
||||
padsize = padpos & 3;
|
||||
if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
|
||||
memmove(skb->data + padsize, skb->data, padpos);
|
||||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ struct ath_buf {
|
||||
u16 bf_flags;
|
||||
struct ath_buf_state bf_state;
|
||||
dma_addr_t bf_dmacontext;
|
||||
struct ath_wiphy *aphy;
|
||||
};
|
||||
|
||||
struct ath_atx_tid {
|
||||
|
||||
@@ -257,14 +257,17 @@ static const struct file_operations fops_interrupt = {
|
||||
|
||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||
int final_ts_idx, idx;
|
||||
int final_ts_idx = 0, idx, i;
|
||||
struct ath_rc_stats *stats;
|
||||
|
||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
if (!rates[i].count)
|
||||
break;
|
||||
|
||||
final_ts_idx = i;
|
||||
}
|
||||
idx = rates[final_ts_idx].idx;
|
||||
stats = &sc->debug.stats.rcstats[idx];
|
||||
stats->success++;
|
||||
|
||||
@@ -390,8 +390,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
||||
ah->config.cck_trig_high = 200;
|
||||
ah->config.cck_trig_low = 100;
|
||||
ah->config.enable_ani = 1;
|
||||
ah->config.diversity_control = ATH9K_ANT_VARIABLE;
|
||||
ah->config.antenna_switch_swap = 0;
|
||||
|
||||
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
|
||||
ah->config.spurchans[i][0] = AR_NO_SPUR;
|
||||
@@ -446,9 +444,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
|
||||
ah->acktimeout = (u32) -1;
|
||||
ah->ctstimeout = (u32) -1;
|
||||
ah->globaltxtimeout = (u32) -1;
|
||||
|
||||
ah->gbeacon_rate = 0;
|
||||
|
||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -1151,7 +1146,7 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
|
||||
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
|
||||
AR_PHY_SWAP_ALT_CHAIN);
|
||||
case 0x3:
|
||||
if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) {
|
||||
if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
|
||||
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
|
||||
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
|
||||
break;
|
||||
@@ -2056,9 +2051,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
ah->ath9k_hw_spur_mitigate_freq(ah, chan);
|
||||
ah->eep_ops->set_board_values(ah, chan);
|
||||
|
||||
if (AR_SREV_5416(ah))
|
||||
ath9k_hw_decrease_chain_power(ah, chan);
|
||||
|
||||
REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
|
||||
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
|
||||
| macStaId1
|
||||
@@ -3518,51 +3510,6 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_setantenna);
|
||||
|
||||
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
|
||||
enum ath9k_ant_setting settings,
|
||||
struct ath9k_channel *chan,
|
||||
u8 *tx_chainmask,
|
||||
u8 *rx_chainmask,
|
||||
u8 *antenna_cfgd)
|
||||
{
|
||||
static u8 tx_chainmask_cfg, rx_chainmask_cfg;
|
||||
|
||||
if (AR_SREV_9280(ah)) {
|
||||
if (!tx_chainmask_cfg) {
|
||||
|
||||
tx_chainmask_cfg = *tx_chainmask;
|
||||
rx_chainmask_cfg = *rx_chainmask;
|
||||
}
|
||||
|
||||
switch (settings) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
*tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
|
||||
*rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
if (ah->caps.tx_chainmask >
|
||||
ATH9K_ANTENNA1_CHAINMASK) {
|
||||
*tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
|
||||
}
|
||||
*rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
*tx_chainmask = tx_chainmask_cfg;
|
||||
*rx_chainmask = rx_chainmask_cfg;
|
||||
*antenna_cfgd = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ah->config.diversity_control = settings;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************/
|
||||
/* General Operation */
|
||||
/*********************/
|
||||
|
||||
@@ -148,21 +148,6 @@ enum wireless_mode {
|
||||
ATH9K_MODE_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* ath9k_ant_setting - transmit antenna settings
|
||||
*
|
||||
* Configures the antenna setting to use for transmit.
|
||||
*
|
||||
* @ATH9K_ANT_VARIABLE: this means transmit on all active antennas
|
||||
* @ATH9K_ANT_FIXED_A: this means transmit on the first antenna only
|
||||
* @ATH9K_ANT_FIXED_B: this means transmit on the second antenna only
|
||||
*/
|
||||
enum ath9k_ant_setting {
|
||||
ATH9K_ANT_VARIABLE = 0,
|
||||
ATH9K_ANT_FIXED_A,
|
||||
ATH9K_ANT_FIXED_B
|
||||
};
|
||||
|
||||
enum ath9k_hw_caps {
|
||||
ATH9K_HW_CAP_MIC_AESCCM = BIT(0),
|
||||
ATH9K_HW_CAP_MIC_CKIP = BIT(1),
|
||||
@@ -226,8 +211,6 @@ struct ath9k_ops_config {
|
||||
u32 cck_trig_high;
|
||||
u32 cck_trig_low;
|
||||
u32 enable_ani;
|
||||
enum ath9k_ant_setting diversity_control;
|
||||
u16 antenna_switch_swap;
|
||||
int serialize_regmode;
|
||||
bool intr_mitigation;
|
||||
#define SPUR_DISABLE 0
|
||||
@@ -572,7 +555,6 @@ struct ath_hw {
|
||||
u32 acktimeout;
|
||||
u32 ctstimeout;
|
||||
u32 globaltxtimeout;
|
||||
u8 gbeacon_rate;
|
||||
|
||||
/* ANI */
|
||||
u32 proc_phyerr;
|
||||
@@ -659,11 +641,6 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
|
||||
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
|
||||
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
|
||||
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
|
||||
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
|
||||
enum ath9k_ant_setting settings,
|
||||
struct ath9k_channel *chan,
|
||||
u8 *tx_chainmask, u8 *rx_chainmask,
|
||||
u8 *antenna_cfgd);
|
||||
|
||||
/* General Operation */
|
||||
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
|
||||
|
||||
@@ -1893,6 +1893,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
hw->channel_change_time = 5000;
|
||||
@@ -2956,90 +2958,62 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
u32 rfilt = 0;
|
||||
int error, i;
|
||||
int error;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
/*
|
||||
* TODO: Need to decide which hw opmode to use for
|
||||
* multi-interface cases
|
||||
* XXX: This belongs into add_interface!
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP &&
|
||||
ah->opmode != NL80211_IFTYPE_AP) {
|
||||
ah->opmode = NL80211_IFTYPE_STATION;
|
||||
ath9k_hw_setopmode(ah);
|
||||
memcpy(common->curbssid, common->macaddr, ETH_ALEN);
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
/* Set BSSID */
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
common->curaid = 0;
|
||||
ath9k_hw_write_associd(ah);
|
||||
/* Request full reset to get hw opmode changed properly */
|
||||
sc->sc_flags |= SC_OP_FULL_RESET;
|
||||
|
||||
/* Set aggregation protection mode parameters */
|
||||
sc->config.ath_aggr_prot = 0;
|
||||
|
||||
/* Only legacy IBSS for now */
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
ath_update_chainmask(sc, 0);
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"BSSID: %pM aid: 0x%x\n",
|
||||
common->curbssid, common->curaid);
|
||||
|
||||
/* need to reconfigure the beacon */
|
||||
sc->sc_flags &= ~SC_OP_BEACONS ;
|
||||
}
|
||||
|
||||
if ((changed & BSS_CHANGED_BSSID) &&
|
||||
!is_zero_ether_addr(bss_conf->bssid)) {
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
/* Set BSSID */
|
||||
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
|
||||
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
common->curaid = 0;
|
||||
ath9k_hw_write_associd(ah);
|
||||
|
||||
/* Set aggregation protection mode parameters */
|
||||
sc->config.ath_aggr_prot = 0;
|
||||
|
||||
ath_print(common, ATH_DBG_CONFIG,
|
||||
"RX filter 0x%x bssid %pM aid 0x%x\n",
|
||||
rfilt, common->curbssid, common->curaid);
|
||||
|
||||
/* need to reconfigure the beacon */
|
||||
sc->sc_flags &= ~SC_OP_BEACONS ;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Enable transmission of beacons (AP, IBSS, MESH) */
|
||||
if ((changed & BSS_CHANGED_BEACON) ||
|
||||
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_ADHOC) ||
|
||||
(vif->type == NL80211_IFTYPE_AP) ||
|
||||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
|
||||
if ((changed & BSS_CHANGED_BEACON) ||
|
||||
(changed & BSS_CHANGED_BEACON_ENABLED &&
|
||||
bss_conf->enable_beacon)) {
|
||||
/*
|
||||
* Allocate and setup the beacon frame.
|
||||
*
|
||||
* Stop any previous beacon DMA. This may be
|
||||
* necessary, for example, when an ibss merge
|
||||
* causes reconfiguration; we may be called
|
||||
* with beacon transmission active.
|
||||
*/
|
||||
/* Disable transmission of beacons */
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
sc->beacon_interval = bss_conf->beacon_int;
|
||||
/*
|
||||
* In case of AP mode, the HW TSF has to be reset
|
||||
* when the beacon interval changes.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
||||
|
||||
error = ath_beacon_alloc(aphy, vif);
|
||||
if (!error)
|
||||
ath_beacon_config(sc, vif);
|
||||
} else {
|
||||
ath_beacon_config(sc, vif);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for WLAN_CAPABILITY_PRIVACY ? */
|
||||
if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
|
||||
for (i = 0; i < IEEE80211_WEP_NKID; i++)
|
||||
if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
|
||||
ath9k_hw_keysetmac(sc->sc_ah,
|
||||
(u16)i,
|
||||
common->curbssid);
|
||||
}
|
||||
|
||||
/* Only legacy IBSS for now */
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
ath_update_chainmask(sc, 0);
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
|
||||
bss_conf->use_short_preamble);
|
||||
@@ -3065,18 +3039,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
ath9k_bss_assoc_info(sc, vif, bss_conf);
|
||||
}
|
||||
|
||||
/*
|
||||
* The HW TSF has to be reset when the beacon interval changes.
|
||||
* We set the flag here, and ath_beacon_config_ap() would take this
|
||||
* into account when it gets called through the subsequent
|
||||
* config_interface() call - with IFCC_BEACON in the changed field.
|
||||
*/
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||
sc->beacon_interval = bss_conf->beacon_int;
|
||||
}
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
@@ -3118,6 +3080,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw)
|
||||
}
|
||||
|
||||
static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn)
|
||||
@@ -3135,11 +3098,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
ath_tx_aggr_start(sc, sta, tid, ssn);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP:
|
||||
ath_tx_aggr_stop(sc, sta, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
ath_tx_aggr_resume(sc, sta, tid);
|
||||
|
||||
@@ -527,95 +527,6 @@ static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath9k_hw_decrease_chain_power()
|
||||
*
|
||||
* @ah: atheros hardware structure
|
||||
* @chan:
|
||||
*
|
||||
* Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios.
|
||||
*
|
||||
* Sets a chain internal RF path to the lowest output power. Any
|
||||
* further writes to bank6 after this setting will override these
|
||||
* changes. Thus this function must be the last function in the
|
||||
* sequence to modify bank 6.
|
||||
*
|
||||
* This function must be called after ar5416SetRfRegs() which is
|
||||
* called from ath9k_hw_process_ini() due to swizzling of bank 6.
|
||||
* Depends on ah->analogBank6Data being initialized by
|
||||
* ath9k_hw_set_rf_regs()
|
||||
*
|
||||
* Additional additive reduction in power -
|
||||
* change chain's switch table so chain's tx state is actually the rx
|
||||
* state value. May produce different results in 2GHz/5GHz as well as
|
||||
* board to board but in general should be a reduction.
|
||||
*
|
||||
* Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be
|
||||
* called after ah->eep_ops->set_board_values() due to RMW of
|
||||
* PHY_SWITCH_CHAIN_0.
|
||||
*/
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
int i, regWrites = 0;
|
||||
u32 bank6SelMask;
|
||||
u32 *bank6Temp = ah->bank6Temp;
|
||||
|
||||
BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
|
||||
|
||||
switch (ah->config.diversity_control) {
|
||||
case ATH9K_ANT_FIXED_A:
|
||||
bank6SelMask =
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */
|
||||
REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */
|
||||
break;
|
||||
case ATH9K_ANT_FIXED_B:
|
||||
bank6SelMask =
|
||||
(ah->config.antenna_switch_swap & ANTSWAP_AB) ?
|
||||
REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */
|
||||
REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */
|
||||
break;
|
||||
case ATH9K_ANT_VARIABLE:
|
||||
return; /* do not change anything */
|
||||
break;
|
||||
default:
|
||||
return; /* do not change anything */
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ah->iniBank6.ia_rows; i++)
|
||||
bank6Temp[i] = ah->analogBank6Data[i];
|
||||
|
||||
/* Write Bank 5 to switch Bank 6 write to selected chain only */
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
|
||||
|
||||
/*
|
||||
* Modify Bank6 selected chain to use lowest amplification.
|
||||
* Modifies the parameters to a value of 1.
|
||||
* Depends on existing bank 6 values to be cached in
|
||||
* ah->analogBank6Data
|
||||
*/
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
|
||||
ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
|
||||
|
||||
REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites);
|
||||
|
||||
REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
|
||||
#ifdef ALTER_SWITCH
|
||||
REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
|
||||
(REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
|
||||
| ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
|
||||
* @ah: atheros hardware stucture
|
||||
@@ -687,7 +598,6 @@ int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
}
|
||||
|
||||
ath9k_hw_force_bias(ah, freq);
|
||||
ath9k_hw_decrease_chain_power(ah, chan);
|
||||
|
||||
reg32 =
|
||||
(channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
|
||||
|
||||
@@ -35,9 +35,6 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
u16 modesIndex);
|
||||
|
||||
void ath9k_hw_decrease_chain_power(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan);
|
||||
|
||||
#define AR_PHY_BASE 0x9800
|
||||
#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
|
||||
|
||||
|
||||
@@ -859,12 +859,12 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
const struct ath_rate_table *rate_table,
|
||||
struct ath_rate_priv *ath_rc_priv,
|
||||
struct ath_tx_info_priv *tx_info_priv,
|
||||
struct ieee80211_tx_info *tx_info,
|
||||
int tx_rate, int xretries, int retries,
|
||||
u32 now_msec)
|
||||
{
|
||||
bool state_change = false;
|
||||
int count;
|
||||
int count, n_bad_frames;
|
||||
u8 last_per;
|
||||
static u32 nretry_to_per_lookup[10] = {
|
||||
100 * 0 / 1,
|
||||
@@ -880,6 +880,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
};
|
||||
|
||||
last_per = ath_rc_priv->per[tx_rate];
|
||||
n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len;
|
||||
|
||||
if (xretries) {
|
||||
if (xretries == 1) {
|
||||
@@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
if (retries >= count)
|
||||
retries = count - 1;
|
||||
|
||||
if (tx_info_priv->n_bad_frames) {
|
||||
if (n_bad_frames) {
|
||||
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
|
||||
* Assuming that n_frames is not 0. The current PER
|
||||
* from the retries is 100 * retries / (retries+1),
|
||||
@@ -920,14 +921,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
* the above PER. The expression below is a
|
||||
* simplified version of the sum of these two terms.
|
||||
*/
|
||||
if (tx_info_priv->n_frames > 0) {
|
||||
int n_frames, n_bad_frames;
|
||||
if (tx_info->status.ampdu_len > 0) {
|
||||
int n_frames, n_bad_tries;
|
||||
u8 cur_per, new_per;
|
||||
|
||||
n_bad_frames = retries * tx_info_priv->n_frames +
|
||||
tx_info_priv->n_bad_frames;
|
||||
n_frames = tx_info_priv->n_frames * (retries + 1);
|
||||
cur_per = (100 * n_bad_frames / n_frames) >> 3;
|
||||
n_bad_tries = retries * tx_info->status.ampdu_len +
|
||||
n_bad_frames;
|
||||
n_frames = tx_info->status.ampdu_len * (retries + 1);
|
||||
cur_per = (100 * n_bad_tries / n_frames) >> 3;
|
||||
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
|
||||
ath_rc_priv->per[tx_rate] = new_per;
|
||||
}
|
||||
@@ -943,8 +944,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
* this was a probe. Otherwise, ignore the probe.
|
||||
*/
|
||||
if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
|
||||
if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
|
||||
tx_info_priv->n_frames) {
|
||||
if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) {
|
||||
/*
|
||||
* Since we probed with just a single attempt,
|
||||
* any retries means the probe failed. Also,
|
||||
@@ -1003,7 +1003,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
|
||||
|
||||
static void ath_rc_update_ht(struct ath_softc *sc,
|
||||
struct ath_rate_priv *ath_rc_priv,
|
||||
struct ath_tx_info_priv *tx_info_priv,
|
||||
struct ieee80211_tx_info *tx_info,
|
||||
int tx_rate, int xretries, int retries)
|
||||
{
|
||||
u32 now_msec = jiffies_to_msecs(jiffies);
|
||||
@@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
|
||||
|
||||
/* Update PER first */
|
||||
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
|
||||
tx_info_priv, tx_rate, xretries,
|
||||
tx_info, tx_rate, xretries,
|
||||
retries, now_msec);
|
||||
|
||||
/*
|
||||
@@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||
struct ieee80211_tx_info *tx_info,
|
||||
int final_ts_idx, int xretries, int long_retry)
|
||||
{
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
const struct ath_rate_table *rate_table;
|
||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||
u8 flags;
|
||||
@@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||
return;
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
ath_rc_update_ht(sc, ath_rc_priv,
|
||||
tx_info_priv, rix,
|
||||
xretries ? 1 : 2,
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info,
|
||||
rix, xretries ? 1 : 2,
|
||||
rates[i].count);
|
||||
}
|
||||
}
|
||||
@@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_softc *sc,
|
||||
return;
|
||||
|
||||
rix = ath_rc_get_rateindex(rate_table, &rates[i]);
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
|
||||
xretries, long_retry);
|
||||
ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
|
||||
}
|
||||
|
||||
static const
|
||||
@@ -1301,23 +1298,30 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
{
|
||||
struct ath_softc *sc = priv;
|
||||
struct ath_rate_priv *ath_rc_priv = priv_sta;
|
||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
int final_ts_idx, tx_status = 0, is_underrun = 0;
|
||||
int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
|
||||
int long_retry = 0;
|
||||
__le16 fc;
|
||||
int i;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = hdr->frame_control;
|
||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
|
||||
if (!rate->count)
|
||||
break;
|
||||
|
||||
final_ts_idx = i;
|
||||
long_retry = rate->count - 1;
|
||||
}
|
||||
|
||||
if (!priv_sta || !ieee80211_is_data(fc) ||
|
||||
!tx_info_priv->update_rc)
|
||||
goto exit;
|
||||
!(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC))
|
||||
return;
|
||||
|
||||
if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
|
||||
goto exit;
|
||||
if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If underrun error is seen assume it as an excessive retry only
|
||||
@@ -1325,20 +1329,17 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
* Adjust the long retry as if the frame was tried hw->max_rate_tries
|
||||
* times. This affects how ratectrl updates PER for the failed rate.
|
||||
*/
|
||||
if (tx_info_priv->tx.ts_flags &
|
||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
|
||||
((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
|
||||
if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
|
||||
(sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
|
||||
tx_status = 1;
|
||||
is_underrun = 1;
|
||||
}
|
||||
|
||||
if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
|
||||
(tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
|
||||
if (tx_info->pad[0] & ATH_TX_INFO_XRETRY)
|
||||
tx_status = 1;
|
||||
|
||||
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
|
||||
(is_underrun) ? sc->hw->max_rate_tries :
|
||||
tx_info_priv->tx.ts_longretry);
|
||||
(is_underrun) ? sc->hw->max_rate_tries : long_retry);
|
||||
|
||||
/* Check if aggregation has to be enabled for this tid */
|
||||
if (conf_is_ht(&sc->hw->conf) &&
|
||||
@@ -1352,13 +1353,11 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
|
||||
if(ath_tx_aggr_check(sc, an, tid))
|
||||
ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid);
|
||||
ieee80211_start_tx_ba_session(sta, tid);
|
||||
}
|
||||
}
|
||||
|
||||
ath_debug_stat_rc(sc, skb);
|
||||
exit:
|
||||
kfree(tx_info_priv);
|
||||
}
|
||||
|
||||
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
||||
|
||||
@@ -167,24 +167,18 @@ struct ath_rate_priv {
|
||||
struct ath_rate_softc *asc;
|
||||
};
|
||||
|
||||
#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0)
|
||||
#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1)
|
||||
#define ATH_TX_INFO_UPDATE_RC (1 << 2)
|
||||
#define ATH_TX_INFO_XRETRY (1 << 3)
|
||||
#define ATH_TX_INFO_UNDERRUN (1 << 4)
|
||||
|
||||
enum ath9k_internal_frame_type {
|
||||
ATH9K_NOT_INTERNAL,
|
||||
ATH9K_INT_PAUSE,
|
||||
ATH9K_INT_UNPAUSE
|
||||
};
|
||||
|
||||
struct ath_tx_info_priv {
|
||||
struct ath_wiphy *aphy;
|
||||
struct ath_tx_status tx;
|
||||
int n_frames;
|
||||
int n_bad_frames;
|
||||
bool update_rc;
|
||||
enum ath9k_internal_frame_type frame_type;
|
||||
};
|
||||
|
||||
#define ATH_TX_INFO_PRIV(tx_info) \
|
||||
((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
|
||||
|
||||
void ath_rate_attach(struct ath_softc *sc);
|
||||
u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
|
||||
int ath_rate_control_register(void);
|
||||
|
||||
@@ -338,13 +338,11 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
|
||||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct ath_wiphy *aphy = hw->priv;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
|
||||
if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
|
||||
if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) &&
|
||||
aphy->state == ATH_WIPHY_PAUSING) {
|
||||
if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
|
||||
if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
|
||||
printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
|
||||
"frame\n", wiphy_name(hw->wiphy));
|
||||
/*
|
||||
@@ -363,9 +361,6 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
|
||||
|
||||
ATH_TXBUF_RESET(tbf);
|
||||
|
||||
tbf->aphy = bf->aphy;
|
||||
tbf->bf_mpdu = bf->bf_mpdu;
|
||||
tbf->bf_buf_addr = bf->bf_buf_addr;
|
||||
*(tbf->bf_desc) = *(bf->bf_desc);
|
||||
@@ -270,7 +271,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ieee80211_hw *hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
struct ath_atx_tid *tid = NULL;
|
||||
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
|
||||
struct ath_desc *ds = bf_last->bf_desc;
|
||||
@@ -284,8 +284,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
|
||||
hw = tx_info_priv->aphy->hw;
|
||||
hw = bf->aphy->hw;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@@ -464,7 +463,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ieee80211_tx_rate *rates;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
u32 max_4ms_framelen, frmlen;
|
||||
u16 aggr_limit, legacy = 0;
|
||||
int i;
|
||||
@@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
|
||||
skb = bf->bf_mpdu;
|
||||
tx_info = IEEE80211_SKB_CB(skb);
|
||||
rates = tx_info->control.rates;
|
||||
tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
|
||||
|
||||
/*
|
||||
* Find the lowest frame length among the rate series that will have a
|
||||
@@ -702,7 +699,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
||||
/* anchor last desc of aggregate */
|
||||
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
|
||||
|
||||
txq->axq_aggr_depth++;
|
||||
ath_tx_txqaddbuf(sc, txq, &bf_q);
|
||||
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
||||
|
||||
@@ -878,8 +874,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
||||
INIT_LIST_HEAD(&txq->axq_acq);
|
||||
spin_lock_init(&txq->axq_lock);
|
||||
txq->axq_depth = 0;
|
||||
txq->axq_aggr_depth = 0;
|
||||
txq->axq_linkbuf = NULL;
|
||||
txq->axq_tx_inprogress = false;
|
||||
sc->tx.txqsetup |= 1<<qnum;
|
||||
}
|
||||
@@ -1014,7 +1008,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
||||
|
||||
if (list_empty(&txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
txq->axq_linkbuf = NULL;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
@@ -1199,7 +1192,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
||||
|
||||
list_splice_tail_init(head, &txq->axq_q);
|
||||
txq->axq_depth++;
|
||||
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
|
||||
|
||||
ath_print(common, ATH_DBG_QUEUE,
|
||||
"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
|
||||
@@ -1560,21 +1552,26 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
||||
struct ath_softc *sc = aphy->sc;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ath_tx_info_priv *tx_info_priv;
|
||||
int hdrlen;
|
||||
__le16 fc;
|
||||
|
||||
tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
|
||||
if (unlikely(!tx_info_priv))
|
||||
return -ENOMEM;
|
||||
tx_info->rate_driver_data[0] = tx_info_priv;
|
||||
tx_info_priv->aphy = aphy;
|
||||
tx_info_priv->frame_type = txctl->frame_type;
|
||||
tx_info->pad[0] = 0;
|
||||
switch (txctl->frame_type) {
|
||||
case ATH9K_NOT_INTERNAL:
|
||||
break;
|
||||
case ATH9K_INT_PAUSE:
|
||||
tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
|
||||
/* fall through */
|
||||
case ATH9K_INT_UNPAUSE:
|
||||
tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
|
||||
break;
|
||||
}
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
fc = hdr->frame_control;
|
||||
|
||||
ATH_TXBUF_RESET(bf);
|
||||
|
||||
bf->aphy = aphy;
|
||||
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
|
||||
|
||||
if (conf_is_ht(&hw->conf) && !is_pae(skb))
|
||||
@@ -1599,8 +1596,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
|
||||
bf->bf_mpdu = NULL;
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
|
||||
"dma_mapping_error() on TX\n");
|
||||
return -ENOMEM;
|
||||
@@ -1781,27 +1776,17 @@ exit:
|
||||
/*****************/
|
||||
|
||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
int tx_flags)
|
||||
struct ath_wiphy *aphy, int tx_flags)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
int hdrlen, padsize;
|
||||
int frame_type = ATH9K_NOT_INTERNAL;
|
||||
|
||||
ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
|
||||
|
||||
if (tx_info_priv) {
|
||||
hw = tx_info_priv->aphy->hw;
|
||||
frame_type = tx_info_priv->frame_type;
|
||||
}
|
||||
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
|
||||
tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
|
||||
kfree(tx_info_priv);
|
||||
tx_info->rate_driver_data[0] = NULL;
|
||||
}
|
||||
if (aphy)
|
||||
hw = aphy->hw;
|
||||
|
||||
if (tx_flags & ATH_TX_BAR)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
@@ -1833,10 +1818,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
SC_OP_WAIT_FOR_TX_ACK));
|
||||
}
|
||||
|
||||
if (frame_type == ATH9K_NOT_INTERNAL)
|
||||
ieee80211_tx_status(hw, skb);
|
||||
else
|
||||
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
|
||||
ath9k_tx_status(hw, skb);
|
||||
else
|
||||
ieee80211_tx_status(hw, skb);
|
||||
}
|
||||
|
||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
@@ -1859,7 +1844,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
||||
}
|
||||
|
||||
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
|
||||
ath_tx_complete(sc, skb, tx_flags);
|
||||
ath_tx_complete(sc, skb, bf->aphy, tx_flags);
|
||||
ath_debug_stat_tx(sc, txq, bf);
|
||||
|
||||
/*
|
||||
@@ -1907,8 +1892,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
|
||||
struct sk_buff *skb = bf->bf_mpdu;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||
struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
|
||||
struct ieee80211_hw *hw = bf->aphy->hw;
|
||||
u8 i, tx_rateindex;
|
||||
|
||||
if (txok)
|
||||
@@ -1917,17 +1901,22 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
|
||||
tx_rateindex = ds->ds_txstat.ts_rateindex;
|
||||
WARN_ON(tx_rateindex >= hw->max_rates);
|
||||
|
||||
tx_info_priv->update_rc = update_rc;
|
||||
if (update_rc)
|
||||
tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;
|
||||
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
|
||||
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
||||
|
||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
||||
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
memcpy(&tx_info_priv->tx, &ds->ds_txstat,
|
||||
sizeof(tx_info_priv->tx));
|
||||
tx_info_priv->n_frames = bf->bf_nframes;
|
||||
tx_info_priv->n_bad_frames = nbad;
|
||||
if (ds->ds_txstat.ts_flags &
|
||||
(ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
|
||||
tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
|
||||
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
|
||||
(ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
|
||||
tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
|
||||
tx_info->status.ampdu_len = bf->bf_nframes;
|
||||
tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1971,7 +1960,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
if (list_empty(&txq->axq_q)) {
|
||||
txq->axq_link = NULL;
|
||||
txq->axq_linkbuf = NULL;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
@@ -2005,10 +1993,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
break;
|
||||
}
|
||||
if (bf->bf_desc == txq->axq_lastdsWithCTS)
|
||||
txq->axq_lastdsWithCTS = NULL;
|
||||
if (ds == txq->axq_gatingds)
|
||||
txq->axq_gatingds = NULL;
|
||||
|
||||
/*
|
||||
* Remove ath_buf's of the same transmit unit from txq,
|
||||
@@ -2022,9 +2006,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
||||
&txq->axq_q, lastbf->list.prev);
|
||||
|
||||
txq->axq_depth--;
|
||||
if (bf_isaggr(bf))
|
||||
txq->axq_aggr_depth--;
|
||||
|
||||
txok = (ds->ds_txstat.ts_status == 0);
|
||||
txq->axq_tx_inprogress = false;
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
|
||||
@@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
||||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
wiphy->reg_notifier = reg_notifier;
|
||||
wiphy->strict_regulatory = true;
|
||||
wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
|
||||
|
||||
if (ath_is_world_regd(reg)) {
|
||||
/*
|
||||
@@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
|
||||
* saved on the wiphy orig_* parameters
|
||||
*/
|
||||
regd = ath_world_regdomain(reg);
|
||||
wiphy->custom_regulatory = true;
|
||||
wiphy->strict_regulatory = false;
|
||||
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
} else {
|
||||
/*
|
||||
* This gets applied in the case of the absense of CRDA,
|
||||
|
||||
@@ -383,44 +383,160 @@ static inline
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if a DMA region fits the device constraints.
|
||||
* Returns true, if the region is OK for usage with this device. */
|
||||
static inline bool b43_dma_address_ok(struct b43_dmaring *ring,
|
||||
dma_addr_t addr, size_t size)
|
||||
{
|
||||
switch (ring->type) {
|
||||
case B43_DMA_30BIT:
|
||||
if ((u64)addr + size > (1ULL << 30))
|
||||
return 0;
|
||||
break;
|
||||
case B43_DMA_32BIT:
|
||||
if ((u64)addr + size > (1ULL << 32))
|
||||
return 0;
|
||||
break;
|
||||
case B43_DMA_64BIT:
|
||||
/* Currently we can't have addresses beyond
|
||||
* 64bit in the kernel. */
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define is_4k_aligned(addr) (((u64)(addr) & 0x0FFFull) == 0)
|
||||
#define is_8k_aligned(addr) (((u64)(addr) & 0x1FFFull) == 0)
|
||||
|
||||
static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base,
|
||||
dma_addr_t dmaaddr, size_t size)
|
||||
{
|
||||
ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE);
|
||||
free_pages((unsigned long)base, get_order(size));
|
||||
}
|
||||
|
||||
static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring,
|
||||
dma_addr_t *dmaaddr, size_t size,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = (void *)__get_free_pages(gfp_flags, get_order(size));
|
||||
if (!base)
|
||||
return NULL;
|
||||
memset(base, 0, size);
|
||||
*dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size,
|
||||
DMA_TO_DEVICE);
|
||||
if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) {
|
||||
free_pages((unsigned long)base, get_order(size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static void * b43_get_and_map_ringmem(struct b43_dmaring *ring,
|
||||
dma_addr_t *dmaaddr, size_t size)
|
||||
{
|
||||
void *base;
|
||||
|
||||
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
|
||||
GFP_KERNEL);
|
||||
if (!base) {
|
||||
b43err(ring->dev->wl, "Failed to allocate or map pages "
|
||||
"for DMA ringmemory\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
|
||||
/* The memory does not fit our device constraints.
|
||||
* Retry with GFP_DMA set to get lower memory. */
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
base = __b43_get_and_map_ringmem(ring, dmaaddr, size,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!base) {
|
||||
b43err(ring->dev->wl, "Failed to allocate or map pages "
|
||||
"in the GFP_DMA region for DMA ringmemory\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!b43_dma_address_ok(ring, *dmaaddr, size)) {
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
b43err(ring->dev->wl, "Failed to allocate DMA "
|
||||
"ringmemory that fits device constraints\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* We expect the memory to be 4k aligned, at least. */
|
||||
if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) {
|
||||
b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static int alloc_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
unsigned int required;
|
||||
void *base;
|
||||
dma_addr_t dmaaddr;
|
||||
|
||||
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
|
||||
* alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
|
||||
* has shown that 4K is sufficient for the latter as long as the buffer
|
||||
* does not cross an 8K boundary.
|
||||
*
|
||||
* For unknown reasons - possibly a hardware error - the BCM4311 rev
|
||||
* 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
|
||||
* which accounts for the GFP_DMA flag below.
|
||||
*
|
||||
* The flags here must match the flags in free_ringmemory below!
|
||||
/* There are several requirements to the descriptor ring memory:
|
||||
* - The memory region needs to fit the address constraints for the
|
||||
* device (same as for frame buffers).
|
||||
* - For 30/32bit DMA devices, the descriptor ring must be 4k aligned.
|
||||
* - For 64bit DMA devices, the descriptor ring must be 8k aligned.
|
||||
*/
|
||||
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
|
||||
B43_DMA_RINGMEMSIZE,
|
||||
&(ring->dmabase), flags);
|
||||
if (!ring->descbase) {
|
||||
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
|
||||
required = ring->nr_slots * sizeof(struct b43_dmadesc64);
|
||||
else
|
||||
required = ring->nr_slots * sizeof(struct b43_dmadesc32);
|
||||
if (B43_WARN_ON(required > 0x1000))
|
||||
return -ENOMEM;
|
||||
|
||||
ring->alloc_descsize = 0x1000;
|
||||
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
ring->alloc_descbase = base;
|
||||
ring->alloc_dmabase = dmaaddr;
|
||||
|
||||
if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) {
|
||||
/* We're on <=32bit DMA, or we already got 8k aligned memory.
|
||||
* That's all we need, so we're fine. */
|
||||
ring->descbase = base;
|
||||
ring->dmabase = dmaaddr;
|
||||
return 0;
|
||||
}
|
||||
memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
|
||||
b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize);
|
||||
|
||||
/* Ok, we failed at the 8k alignment requirement.
|
||||
* Try to force-align the memory region now. */
|
||||
ring->alloc_descsize = 0x2000;
|
||||
base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
ring->alloc_descbase = base;
|
||||
ring->alloc_dmabase = dmaaddr;
|
||||
|
||||
if (is_8k_aligned(dmaaddr)) {
|
||||
/* We're already 8k aligned. That Ok, too. */
|
||||
ring->descbase = base;
|
||||
ring->dmabase = dmaaddr;
|
||||
return 0;
|
||||
}
|
||||
/* Force-align it to 8k */
|
||||
ring->descbase = (void *)((u8 *)base + 0x1000);
|
||||
ring->dmabase = dmaaddr + 0x1000;
|
||||
B43_WARN_ON(!is_8k_aligned(ring->dmabase));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_ringmemory(struct b43_dmaring *ring)
|
||||
{
|
||||
gfp_t flags = GFP_KERNEL;
|
||||
|
||||
if (ring->type == B43_DMA_64BIT)
|
||||
flags |= GFP_DMA;
|
||||
|
||||
ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
|
||||
ring->descbase, ring->dmabase, flags);
|
||||
b43_unmap_and_free_ringmem(ring, ring->alloc_descbase,
|
||||
ring->alloc_dmabase, ring->alloc_descsize);
|
||||
}
|
||||
|
||||
/* Reset the RX DMA channel */
|
||||
@@ -530,29 +646,14 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
|
||||
if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
|
||||
return 1;
|
||||
|
||||
switch (ring->type) {
|
||||
case B43_DMA_30BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 30))
|
||||
goto address_error;
|
||||
break;
|
||||
case B43_DMA_32BIT:
|
||||
if ((u64)addr + buffersize > (1ULL << 32))
|
||||
goto address_error;
|
||||
break;
|
||||
case B43_DMA_64BIT:
|
||||
/* Currently we can't have addresses beyond
|
||||
* 64bit in the kernel. */
|
||||
break;
|
||||
if (!b43_dma_address_ok(ring, addr, buffersize)) {
|
||||
/* We can't support this address. Unmap it again. */
|
||||
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The address is OK. */
|
||||
return 0;
|
||||
|
||||
address_error:
|
||||
/* We can't support this address. Unmap it again. */
|
||||
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
|
||||
@@ -614,6 +715,9 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
|
||||
meta->dmaaddr = dmaaddr;
|
||||
ring->ops->fill_descriptor(ring, desc, dmaaddr,
|
||||
ring->rx_buffersize, 0, 0, 0);
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
ring->alloc_dmabase,
|
||||
ring->alloc_descsize, DMA_TO_DEVICE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -770,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring)
|
||||
for (i = 0; i < ring->nr_slots; i++) {
|
||||
desc = ring->ops->idx2desc(ring, i, &meta);
|
||||
|
||||
if (!meta->skb) {
|
||||
if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) {
|
||||
B43_WARN_ON(!ring->tx);
|
||||
continue;
|
||||
}
|
||||
@@ -822,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
||||
enum b43_dmatype type)
|
||||
{
|
||||
struct b43_dmaring *ring;
|
||||
int err;
|
||||
int i, err;
|
||||
dma_addr_t dma_test;
|
||||
|
||||
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
|
||||
@@ -837,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
|
||||
GFP_KERNEL);
|
||||
if (!ring->meta)
|
||||
goto err_kfree_ring;
|
||||
for (i = 0; i < ring->nr_slots; i++)
|
||||
ring->meta->skb = B43_DMA_PTR_POISON;
|
||||
|
||||
ring->type = type;
|
||||
ring->dev = dev;
|
||||
@@ -1147,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
|
||||
case 0x5000:
|
||||
ring = dma->tx_ring_mcast;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
*slot = (cookie & 0x0FFF);
|
||||
B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
|
||||
if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) {
|
||||
b43dbg(dev->wl, "TX-status contains "
|
||||
"invalid cookie: 0x%04X\n", cookie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ring;
|
||||
}
|
||||
@@ -1246,6 +1354,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
|
||||
}
|
||||
/* Now transfer the whole frame. */
|
||||
wmb();
|
||||
ssb_dma_sync_single_for_device(ring->dev->dev,
|
||||
ring->alloc_dmabase,
|
||||
ring->alloc_descsize, DMA_TO_DEVICE);
|
||||
ops->poke_tx(ring, next_slot(ring, slot));
|
||||
return 0;
|
||||
|
||||
@@ -1387,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||
struct b43_dmaring *ring;
|
||||
struct b43_dmadesc_generic *desc;
|
||||
struct b43_dmadesc_meta *meta;
|
||||
int slot;
|
||||
int slot, firstused;
|
||||
bool frame_succeed;
|
||||
|
||||
ring = parse_cookie(dev, status->cookie, &slot);
|
||||
if (unlikely(!ring))
|
||||
return;
|
||||
|
||||
B43_WARN_ON(!ring->tx);
|
||||
|
||||
/* Sanity check: TX packets are processed in-order on one ring.
|
||||
* Check if the slot deduced from the cookie really is the first
|
||||
* used slot. */
|
||||
firstused = ring->current_slot - ring->used_slots + 1;
|
||||
if (firstused < 0)
|
||||
firstused = ring->nr_slots + firstused;
|
||||
if (unlikely(slot != firstused)) {
|
||||
/* This possibly is a firmware bug and will result in
|
||||
* malfunction, memory leaks and/or stall of DMA functionality. */
|
||||
b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
|
||||
"Expected %d, but got %d\n",
|
||||
ring->index, firstused, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
ops = ring->ops;
|
||||
while (1) {
|
||||
B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
|
||||
B43_WARN_ON(slot < 0 || slot >= ring->nr_slots);
|
||||
desc = ops->idx2desc(ring, slot, &meta);
|
||||
|
||||
if (b43_dma_ptr_is_poisoned(meta->skb)) {
|
||||
b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) "
|
||||
"on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
if (meta->skb) {
|
||||
struct b43_private_tx_info *priv_info =
|
||||
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
|
||||
@@ -1415,7 +1547,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||
if (meta->is_last_fragment) {
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
BUG_ON(!meta->skb);
|
||||
if (unlikely(!meta->skb)) {
|
||||
/* This is a scatter-gather fragment of a frame, so
|
||||
* the skb pointer must not be NULL. */
|
||||
b43dbg(dev->wl, "TX status unexpected NULL skb "
|
||||
"at slot %d (first=%d) on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(meta->skb);
|
||||
|
||||
@@ -1433,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||
#endif /* DEBUG */
|
||||
ieee80211_tx_status(dev->wl->hw, meta->skb);
|
||||
|
||||
/* skb is freed by ieee80211_tx_status() */
|
||||
meta->skb = NULL;
|
||||
/* skb will be freed by ieee80211_tx_status().
|
||||
* Poison our pointer. */
|
||||
meta->skb = B43_DMA_PTR_POISON;
|
||||
} else {
|
||||
/* No need to call free_descriptor_buffer here, as
|
||||
* this is only the txhdr, which is not allocated.
|
||||
*/
|
||||
B43_WARN_ON(meta->skb);
|
||||
if (unlikely(meta->skb)) {
|
||||
b43dbg(dev->wl, "TX status unexpected non-NULL skb "
|
||||
"at slot %d (first=%d) on ring %d\n",
|
||||
slot, firstused, ring->index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Everything unmapped and free'd. So it's not used anymore. */
|
||||
ring->used_slots--;
|
||||
|
||||
if (meta->is_last_fragment)
|
||||
if (meta->is_last_fragment) {
|
||||
/* This is the last scatter-gather
|
||||
* fragment of the frame. We are done. */
|
||||
break;
|
||||
}
|
||||
slot = next_slot(ring, slot);
|
||||
}
|
||||
if (ring->stopped) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef B43_DMA_H_
|
||||
#define B43_DMA_H_
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "b43.h"
|
||||
|
||||
@@ -157,7 +157,6 @@ struct b43_dmadesc_generic {
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* Misc DMA constants */
|
||||
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
|
||||
#define B43_DMA0_RX_FRAMEOFFSET 30
|
||||
|
||||
/* DMA engine tuning knobs */
|
||||
@@ -165,6 +164,10 @@ struct b43_dmadesc_generic {
|
||||
#define B43_RXRING_SLOTS 64
|
||||
#define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN
|
||||
|
||||
/* Pointer poison */
|
||||
#define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM))
|
||||
#define b43_dma_ptr_is_poisoned(ptr) (unlikely((ptr) == B43_DMA_PTR_POISON))
|
||||
|
||||
|
||||
struct sk_buff;
|
||||
struct b43_private;
|
||||
@@ -243,6 +246,12 @@ struct b43_dmaring {
|
||||
/* The QOS priority assigned to this ring. Only used for TX rings.
|
||||
* This is the mac80211 "queue" value. */
|
||||
u8 queue_prio;
|
||||
/* Pointers and size of the originally allocated and mapped memory
|
||||
* region for the descriptor ring. */
|
||||
void *alloc_descbase;
|
||||
dma_addr_t alloc_dmabase;
|
||||
unsigned int alloc_descsize;
|
||||
/* Pointer to our wireless device. */
|
||||
struct b43_wldev *dev;
|
||||
#ifdef CONFIG_B43_DEBUG
|
||||
/* Maximum number of used slots. */
|
||||
|
||||
@@ -296,6 +296,33 @@ static const char *command_types[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#define WEXT_USECHANNELS 1
|
||||
|
||||
static const long ipw2100_frequencies[] = {
|
||||
2412, 2417, 2422, 2427,
|
||||
2432, 2437, 2442, 2447,
|
||||
2452, 2457, 2462, 2467,
|
||||
2472, 2484
|
||||
};
|
||||
|
||||
#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
|
||||
|
||||
static const long ipw2100_rates_11b[] = {
|
||||
1000000,
|
||||
2000000,
|
||||
5500000,
|
||||
11000000
|
||||
};
|
||||
|
||||
static struct ieee80211_rate ipw2100_bg_rates[] = {
|
||||
{ .bitrate = 10 },
|
||||
{ .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
{ .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
|
||||
};
|
||||
|
||||
#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
|
||||
|
||||
/* Pre-decl until we get the code solid and then we can clean it up */
|
||||
static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
|
||||
static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
|
||||
@@ -1141,6 +1168,7 @@ static int rf_kill_active(struct ipw2100_priv *priv)
|
||||
int i;
|
||||
|
||||
if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||
priv->status &= ~STATUS_RF_KILL_HW;
|
||||
return 0;
|
||||
}
|
||||
@@ -1151,10 +1179,13 @@ static int rf_kill_active(struct ipw2100_priv *priv)
|
||||
value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
if (value == 0) {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
else
|
||||
} else {
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
|
||||
priv->status &= ~STATUS_RF_KILL_HW;
|
||||
}
|
||||
|
||||
return (value == 0);
|
||||
}
|
||||
@@ -1814,13 +1845,6 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Called by register_netdev() */
|
||||
static int ipw2100_net_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
return ipw2100_up(priv, 1);
|
||||
}
|
||||
|
||||
static void ipw2100_down(struct ipw2100_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -1875,6 +1899,64 @@ static void ipw2100_down(struct ipw2100_priv *priv)
|
||||
netif_stop_queue(priv->net_dev);
|
||||
}
|
||||
|
||||
/* Called by register_netdev() */
|
||||
static int ipw2100_net_init(struct net_device *dev)
|
||||
{
|
||||
struct ipw2100_priv *priv = libipw_priv(dev);
|
||||
const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
|
||||
struct wireless_dev *wdev = &priv->ieee->wdev;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = ipw2100_up(priv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
|
||||
|
||||
/* fill-out priv->ieee->bg_band */
|
||||
if (geo->bg_channels) {
|
||||
struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
|
||||
|
||||
bg_band->band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->n_channels = geo->bg_channels;
|
||||
bg_band->channels =
|
||||
kzalloc(geo->bg_channels *
|
||||
sizeof(struct ieee80211_channel), GFP_KERNEL);
|
||||
/* translate geo->bg to bg_band.channels */
|
||||
for (i = 0; i < geo->bg_channels; i++) {
|
||||
bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
|
||||
bg_band->channels[i].center_freq = geo->bg[i].freq;
|
||||
bg_band->channels[i].hw_value = geo->bg[i].channel;
|
||||
bg_band->channels[i].max_power = geo->bg[i].max_power;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_PASSIVE_SCAN;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_NO_IBSS;
|
||||
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
|
||||
bg_band->channels[i].flags |=
|
||||
IEEE80211_CHAN_RADAR;
|
||||
/* No equivalent for LIBIPW_CH_80211H_RULES,
|
||||
LIBIPW_CH_UNIFORM_SPREADING, or
|
||||
LIBIPW_CH_B_ONLY... */
|
||||
}
|
||||
/* point at bitrate info */
|
||||
bg_band->bitrates = ipw2100_bg_rates;
|
||||
bg_band->n_bitrates = RATE_COUNT;
|
||||
|
||||
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
|
||||
}
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
|
||||
if (wiphy_register(wdev->wiphy)) {
|
||||
ipw2100_down(priv);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipw2100_reset_adapter(struct work_struct *work)
|
||||
{
|
||||
struct ipw2100_priv *priv =
|
||||
@@ -2090,6 +2172,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
|
||||
priv->net_dev->name);
|
||||
|
||||
/* RF_KILL is now enabled (else we wouldn't be here) */
|
||||
wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
|
||||
priv->status |= STATUS_RF_KILL_HW;
|
||||
|
||||
/* Make sure the RF Kill check timer is running */
|
||||
@@ -6029,7 +6112,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
|
||||
struct ipw2100_priv *priv;
|
||||
struct net_device *dev;
|
||||
|
||||
dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
|
||||
dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
priv = libipw_priv(dev);
|
||||
@@ -6342,7 +6425,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
||||
sysfs_remove_group(&pci_dev->dev.kobj,
|
||||
&ipw2100_attribute_group);
|
||||
|
||||
free_ieee80211(dev);
|
||||
free_ieee80211(dev, 0);
|
||||
pci_set_drvdata(pci_dev, NULL);
|
||||
}
|
||||
|
||||
@@ -6400,7 +6483,10 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
|
||||
if (dev->base_addr)
|
||||
iounmap((void __iomem *)dev->base_addr);
|
||||
|
||||
free_ieee80211(dev);
|
||||
/* wiphy_unregister needs to be here, before free_ieee80211 */
|
||||
wiphy_unregister(priv->ieee->wdev.wiphy);
|
||||
kfree(priv->ieee->bg_band.channels);
|
||||
free_ieee80211(dev, 0);
|
||||
}
|
||||
|
||||
pci_release_regions(pci_dev);
|
||||
@@ -6601,26 +6687,6 @@ static void __exit ipw2100_exit(void)
|
||||
module_init(ipw2100_init);
|
||||
module_exit(ipw2100_exit);
|
||||
|
||||
#define WEXT_USECHANNELS 1
|
||||
|
||||
static const long ipw2100_frequencies[] = {
|
||||
2412, 2417, 2422, 2427,
|
||||
2432, 2437, 2442, 2447,
|
||||
2452, 2457, 2462, 2467,
|
||||
2472, 2484
|
||||
};
|
||||
|
||||
#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
|
||||
|
||||
static const long ipw2100_rates_11b[] = {
|
||||
1000000,
|
||||
2000000,
|
||||
5500000,
|
||||
11000000
|
||||
};
|
||||
|
||||
#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
|
||||
|
||||
static int ipw2100_wx_get_name(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *wrqu, char *extra)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user