Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller
2009-11-24 15:01:29 -08:00
125 changed files with 3168 additions and 1941 deletions

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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 {

View File

@@ -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++;

View File

@@ -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 */
/*********************/

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) |

View File

@@ -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))

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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. */

View File

@@ -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