Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem

This commit is contained in:
John W. Linville 2013-05-29 10:59:35 -04:00
commit 50cc1cab4c
27 changed files with 301 additions and 235 deletions

View File

@ -68,13 +68,16 @@
#define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR 0x3ff
#define AR9300_BASE_ADDR_512 0x1ff #define AR9300_BASE_ADDR_512 0x1ff
#define AR9300_OTP_BASE (AR_SREV_9340(ah) ? 0x30000 : 0x14000) #define AR9300_OTP_BASE \
#define AR9300_OTP_STATUS (AR_SREV_9340(ah) ? 0x30018 : 0x15f18) ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
#define AR9300_OTP_STATUS \
((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
#define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_TYPE 0x7
#define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_VALID 0x4
#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
#define AR9300_OTP_STATUS_SM_BUSY 0x1 #define AR9300_OTP_STATUS_SM_BUSY 0x1
#define AR9300_OTP_READ_DATA (AR_SREV_9340(ah) ? 0x3001c : 0x15f1c) #define AR9300_OTP_READ_DATA \
((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
enum targetPowerHTRates { enum targetPowerHTRates {
HT_TARGET_RATE_0_8_16, HT_TARGET_RATE_0_8_16,

View File

@ -334,7 +334,8 @@ static void ar9003_hw_spur_ofdm(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);
if (REG_READ_FIELD(ah, AR_PHY_MODE, if (!AR_SREV_9340(ah) &&
REG_READ_FIELD(ah, AR_PHY_MODE,
AR_PHY_MODE_DYNAMIC) == 0x1) AR_PHY_MODE_DYNAMIC) == 0x1)
REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);

View File

@ -251,10 +251,9 @@ struct ath_atx_tid {
int tidno; int tidno;
int baw_head; /* first un-acked tx buffer */ int baw_head; /* first un-acked tx buffer */
int baw_tail; /* next unused tx buffer slot */ int baw_tail; /* next unused tx buffer slot */
int sched; bool sched;
int paused; bool paused;
u8 state; bool active;
bool stop_cb;
}; };
struct ath_node { struct ath_node {
@ -275,10 +274,6 @@ struct ath_node {
#endif #endif
}; };
#define AGGR_CLEANUP BIT(1)
#define AGGR_ADDBA_COMPLETE BIT(2)
#define AGGR_ADDBA_PROGRESS BIT(3)
struct ath_tx_control { struct ath_tx_control {
struct ath_txq *txq; struct ath_txq *txq;
struct ath_node *an; struct ath_node *an;
@ -352,8 +347,7 @@ void ath_tx_tasklet(struct ath_softc *sc);
void ath_tx_edma_tasklet(struct ath_softc *sc); void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn); u16 tid, u16 *ssn);
bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
bool flush);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);

View File

@ -1172,6 +1172,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
static inline void ath9k_hw_set_dma(struct ath_hw *ah) static inline void ath9k_hw_set_dma(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
int txbuf_size;
ENABLE_REGWRITE_BUFFER(ah); ENABLE_REGWRITE_BUFFER(ah);
@ -1225,13 +1226,17 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
* So set the usable tx buf size also to half to * So set the usable tx buf size also to half to
* avoid data/delimiter underruns * avoid data/delimiter underruns
*/ */
REG_WRITE(ah, AR_PCU_TXBUF_CTRL, txbuf_size = AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE;
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); } else if (AR_SREV_9340_13_OR_LATER(ah)) {
} else if (!AR_SREV_9271(ah)) { /* Uses fewer entries for AR934x v1.3+ to prevent rx overruns */
REG_WRITE(ah, AR_PCU_TXBUF_CTRL, txbuf_size = AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE;
AR_PCU_TXBUF_CTRL_USABLE_SIZE); } else {
txbuf_size = AR_PCU_TXBUF_CTRL_USABLE_SIZE;
} }
if (!AR_SREV_9271(ah))
REG_WRITE(ah, AR_PCU_TXBUF_CTRL, txbuf_size);
REGWRITE_BUFFER_FLUSH(ah); REGWRITE_BUFFER_FLUSH(ah);
if (AR_SREV_9300_20_OR_LATER(ah)) if (AR_SREV_9300_20_OR_LATER(ah))
@ -1306,9 +1311,13 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
} else { } else {
tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
if (tmpReg & if (AR_SREV_9340(ah))
(AR_INTR_SYNC_LOCAL_TIMEOUT | tmpReg &= AR9340_INTR_SYNC_LOCAL_TIMEOUT;
AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { else
tmpReg &= AR_INTR_SYNC_LOCAL_TIMEOUT |
AR_INTR_SYNC_RADM_CPL_TIMEOUT;
if (tmpReg) {
u32 val; u32 val;
REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);

View File

@ -410,7 +410,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
if (AR_SREV_9340(ah)) if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah))
REG_WRITE(ah, AR_DMISC(q), REG_WRITE(ah, AR_DMISC(q),
AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1); AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
else else

View File

@ -1709,7 +1709,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
flush = true; flush = true;
case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_CONT:
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
if (ath_tx_aggr_stop(sc, sta, tid, flush)) ath_tx_aggr_stop(sc, sta, tid);
if (!flush)
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
break; break;

View File

@ -1227,10 +1227,7 @@ static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta,
return false; return false;
txtid = ATH_AN_2_TID(an, tidno); txtid = ATH_AN_2_TID(an, tidno);
return !txtid->active;
if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
return false;
} }

View File

@ -798,6 +798,10 @@
#define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_10 0
#define AR_SREV_REVISION_9485_11 1 #define AR_SREV_REVISION_9485_11 1
#define AR_SREV_VERSION_9340 0x300 #define AR_SREV_VERSION_9340 0x300
#define AR_SREV_REVISION_9340_10 0
#define AR_SREV_REVISION_9340_11 1
#define AR_SREV_REVISION_9340_12 2
#define AR_SREV_REVISION_9340_13 3
#define AR_SREV_VERSION_9580 0x1C0 #define AR_SREV_VERSION_9580 0x1C0
#define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */
#define AR_SREV_VERSION_9462 0x280 #define AR_SREV_VERSION_9462 0x280
@ -897,6 +901,10 @@
#define AR_SREV_9340(_ah) \ #define AR_SREV_9340(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
#define AR_SREV_9340_13_OR_LATER(_ah) \
(AR_SREV_9340((_ah)) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13))
#define AR_SREV_9285E_20(_ah) \ #define AR_SREV_9285E_20(_ah) \
(AR_SREV_9285_12_OR_LATER(_ah) && \ (AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
@ -1007,6 +1015,8 @@ enum {
AR_INTR_SYNC_LOCAL_TIMEOUT | AR_INTR_SYNC_LOCAL_TIMEOUT |
AR_INTR_SYNC_MAC_SLEEP_ACCESS), AR_INTR_SYNC_MAC_SLEEP_ACCESS),
AR9340_INTR_SYNC_LOCAL_TIMEOUT = 0x00000010,
AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF, AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF,
}; };
@ -1881,6 +1891,7 @@ enum {
#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF #define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF
#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 #define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700
#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380 #define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380
#define AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE 0x500
#define AR_PCU_MISC_MODE2 0x8344 #define AR_PCU_MISC_MODE2 0x8344
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002

View File

@ -125,24 +125,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
list_add_tail(&ac->list, &txq->axq_acq); list_add_tail(&ac->list, &txq->axq_acq);
} }
static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->ac->txq;
WARN_ON(!tid->paused);
ath_txq_lock(sc, txq);
tid->paused = false;
if (skb_queue_empty(&tid->buf_q))
goto unlock;
ath_tx_queue_tid(txq, tid);
ath_txq_schedule(sc, txq);
unlock:
ath_txq_unlock_complete(sc, txq);
}
static struct ath_frame_info *get_frame_info(struct sk_buff *skb) static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{ {
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@ -164,20 +146,7 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
ARRAY_SIZE(bf->rates)); ARRAY_SIZE(bf->rates));
} }
static void ath_tx_clear_tid(struct ath_softc *sc, struct ath_atx_tid *tid) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_CLEANUP;
if (!tid->stop_cb)
return;
ieee80211_start_tx_ba_cb_irqsafe(tid->an->vif, tid->an->sta->addr,
tid->tidno);
tid->stop_cb = false;
}
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
bool flush_packets)
{ {
struct ath_txq *txq = tid->ac->txq; struct ath_txq *txq = tid->ac->txq;
struct sk_buff *skb; struct sk_buff *skb;
@ -194,15 +163,16 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
while ((skb = __skb_dequeue(&tid->buf_q))) { while ((skb = __skb_dequeue(&tid->buf_q))) {
fi = get_frame_info(skb); fi = get_frame_info(skb);
bf = fi->bf; bf = fi->bf;
if (!bf && !flush_packets)
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) { if (!bf) {
ieee80211_free_txskb(sc->hw, skb); bf = ath_tx_setup_buffer(sc, txq, tid, skb);
continue; if (!bf) {
ieee80211_free_txskb(sc->hw, skb);
continue;
}
} }
if (fi->retries || flush_packets) { if (fi->retries) {
list_add_tail(&bf->list, &bf_head); list_add_tail(&bf->list, &bf_head);
ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
@ -213,10 +183,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid,
} }
} }
if (tid->baw_head == tid->baw_tail) if (sendbar) {
ath_tx_clear_tid(sc, tid);
if (sendbar && !flush_packets) {
ath_txq_unlock(sc, txq); ath_txq_unlock(sc, txq);
ath_send_bar(tid, tid->seq_start); ath_send_bar(tid, tid->seq_start);
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
@ -499,19 +466,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
fi = get_frame_info(skb); fi = get_frame_info(skb);
if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
/*
* Outside of the current BlockAck window,
* maybe part of a previous session
*/
txfail = 1;
} else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
/* transmit completion, subframe is /* transmit completion, subframe is
* acked by block ack */ * acked by block ack */
acked_cnt++; acked_cnt++;
} else if (!isaggr && txok) { } else if (!isaggr && txok) {
/* transmit completion */ /* transmit completion */
acked_cnt++; acked_cnt++;
} else if (tid->state & AGGR_CLEANUP) {
/*
* cleanup in progress, just fail
* the un-acked sub-frames
*/
txfail = 1;
} else if (flush) { } else if (flush) {
txpending = 1; txpending = 1;
} else if (fi->retries < ATH_MAX_SW_RETRIES) { } else if (fi->retries < ATH_MAX_SW_RETRIES) {
@ -535,7 +502,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (bf_next != NULL || !bf_last->bf_stale) if (bf_next != NULL || !bf_last->bf_stale)
list_move_tail(&bf->list, &bf_head); list_move_tail(&bf->list, &bf_head);
if (!txpending || (tid->state & AGGR_CLEANUP)) { if (!txpending) {
/* /*
* complete the acked-ones/xretried ones; update * complete the acked-ones/xretried ones; update
* block-ack window * block-ack window
@ -609,9 +576,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
} }
if (tid->state & AGGR_CLEANUP)
ath_tx_flush_tid(sc, tid, false);
rcu_read_unlock(); rcu_read_unlock();
if (needreset) if (needreset)
@ -1244,9 +1208,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an = (struct ath_node *)sta->drv_priv; an = (struct ath_node *)sta->drv_priv;
txtid = ATH_AN_2_TID(an, tid); txtid = ATH_AN_2_TID(an, tid);
if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
return -EAGAIN;
/* update ampdu factor/density, they may have changed. This may happen /* update ampdu factor/density, they may have changed. This may happen
* in HT IBSS when a beacon with HT-info is received after the station * in HT IBSS when a beacon with HT-info is received after the station
* has already been added. * has already been added.
@ -1258,7 +1219,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density; an->mpdudensity = density;
} }
txtid->state |= AGGR_ADDBA_PROGRESS; txtid->active = true;
txtid->paused = true; txtid->paused = true;
*ssn = txtid->seq_start = txtid->seq_next; *ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1; txtid->bar_index = -1;
@ -1269,45 +1230,17 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
return 0; return 0;
} }
bool ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
bool flush)
{ {
struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
struct ath_txq *txq = txtid->ac->txq; struct ath_txq *txq = txtid->ac->txq;
bool ret = !flush;
if (flush)
txtid->stop_cb = false;
if (txtid->state & AGGR_CLEANUP)
return false;
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
return ret;
}
ath_txq_lock(sc, txq); ath_txq_lock(sc, txq);
txtid->active = false;
txtid->paused = true; txtid->paused = true;
ath_tx_flush_tid(sc, txtid);
/*
* If frames are still being transmitted for this TID, they will be
* cleaned up during tx completion. To prevent race conditions, this
* TID can only be reused after all in-progress subframes have been
* completed.
*/
if (txtid->baw_head != txtid->baw_tail) {
txtid->state |= AGGR_CLEANUP;
ret = false;
txtid->stop_cb = !flush;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
}
ath_tx_flush_tid(sc, txtid, flush);
ath_txq_unlock_complete(sc, txq); ath_txq_unlock_complete(sc, txq);
return ret;
} }
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@ -1371,18 +1304,28 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
} }
} }
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tidno)
{ {
struct ath_atx_tid *txtid; struct ath_atx_tid *tid;
struct ath_node *an; struct ath_node *an;
struct ath_txq *txq;
an = (struct ath_node *)sta->drv_priv; an = (struct ath_node *)sta->drv_priv;
tid = ATH_AN_2_TID(an, tidno);
txq = tid->ac->txq;
txtid = ATH_AN_2_TID(an, tid); ath_txq_lock(sc, txq);
txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
txtid->state |= AGGR_ADDBA_COMPLETE; tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
txtid->state &= ~AGGR_ADDBA_PROGRESS; tid->paused = false;
ath_tx_resume_tid(sc, txtid);
if (!skb_queue_empty(&tid->buf_q)) {
ath_tx_queue_tid(txq, tid);
ath_txq_schedule(sc, txq);
}
ath_txq_unlock_complete(sc, txq);
} }
/********************/ /********************/
@ -2431,13 +2374,10 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->baw_head = tid->baw_tail = 0; tid->baw_head = tid->baw_tail = 0;
tid->sched = false; tid->sched = false;
tid->paused = false; tid->paused = false;
tid->state &= ~AGGR_CLEANUP; tid->active = false;
__skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->buf_q);
acno = TID_TO_WME_AC(tidno); acno = TID_TO_WME_AC(tidno);
tid->ac = &an->ac[acno]; tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
tid->stop_cb = false;
} }
for (acno = 0, ac = &an->ac[acno]; for (acno = 0, ac = &an->ac[acno];
@ -2474,7 +2414,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
} }
ath_tid_drain(sc, txq, tid); ath_tid_drain(sc, txq, tid);
ath_tx_clear_tid(sc, tid); tid->active = false;
ath_txq_unlock(sc, txq); ath_txq_unlock(sc, txq);
} }

View File

@ -1624,7 +1624,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
netif_carrier_off(dev); netif_carrier_off(dev);
if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv)); if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv))
printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",

View File

@ -27,7 +27,6 @@
#include "tracepoint.h" #include "tracepoint.h"
#define PKTFILTER_BUF_SIZE 128 #define PKTFILTER_BUF_SIZE 128
#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
#define BRCMF_DEFAULT_BCN_TIMEOUT 3 #define BRCMF_DEFAULT_BCN_TIMEOUT 3
#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
@ -338,23 +337,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
goto done; goto done;
} }
/* Try to set and enable ARP offload feature, this may fail */
err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
if (err) {
brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
BRCMF_ARPOL_MODE, err);
err = 0;
} else {
err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
if (err) {
brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
err);
err = 0;
} else
brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
BRCMF_ARPOL_MODE);
}
/* Setup packet filter */ /* Setup packet filter */
brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER); brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER, brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,

View File

@ -653,10 +653,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
ndev->destructor = free_netdev;
return 0; return 0;
fail: fail:
drvr->iflist[ifp->bssidx] = NULL;
ndev->netdev_ops = NULL; ndev->netdev_ops = NULL;
free_netdev(ndev);
return -EBADE; return -EBADE;
} }
@ -720,6 +723,9 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
return 0; return 0;
fail: fail:
ifp->drvr->iflist[ifp->bssidx] = NULL;
ndev->netdev_ops = NULL;
free_netdev(ndev);
return -EBADE; return -EBADE;
} }
@ -788,6 +794,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
struct brcmf_if *ifp; struct brcmf_if *ifp;
ifp = drvr->iflist[bssidx]; ifp = drvr->iflist[bssidx];
drvr->iflist[bssidx] = NULL;
if (!ifp) { if (!ifp) {
brcmf_err("Null interface, idx=%d\n", bssidx); brcmf_err("Null interface, idx=%d\n", bssidx);
return; return;
@ -808,15 +815,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
cancel_work_sync(&ifp->setmacaddr_work); cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->multicast_work);
} }
/* unregister will take care of freeing it */
unregister_netdev(ifp->ndev); unregister_netdev(ifp->ndev);
if (bssidx == 0) if (bssidx == 0)
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
free_netdev(ifp->ndev);
} else { } else {
kfree(ifp); kfree(ifp);
} }
drvr->iflist[bssidx] = NULL;
} }
int brcmf_attach(uint bus_hdrlen, struct device *dev) int brcmf_attach(uint bus_hdrlen, struct device *dev)
@ -925,8 +930,6 @@ int brcmf_bus_start(struct device *dev)
brcmf_fws_del_interface(ifp); brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr); brcmf_fws_deinit(drvr);
} }
free_netdev(ifp->ndev);
drvr->iflist[0] = NULL;
if (p2p_ifp) { if (p2p_ifp) {
free_netdev(p2p_ifp->ndev); free_netdev(p2p_ifp->ndev);
drvr->iflist[1] = NULL; drvr->iflist[1] = NULL;
@ -934,7 +937,8 @@ int brcmf_bus_start(struct device *dev)
return ret; return ret;
} }
if ((brcmf_p2p_enable) && (p2p_ifp)) if ((brcmf_p2p_enable) && (p2p_ifp))
brcmf_net_p2p_attach(p2p_ifp); if (brcmf_net_p2p_attach(p2p_ifp) < 0)
brcmf_p2p_enable = 0;
return 0; return 0;
} }

View File

@ -202,7 +202,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
return; return;
brcmf_fws_add_interface(ifp); brcmf_fws_add_interface(ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp, false); if (brcmf_net_attach(ifp, false) < 0)
return;
} }
if (ifevent->action == BRCMF_E_IF_CHANGE) if (ifevent->action == BRCMF_E_IF_CHANGE)

View File

@ -23,6 +23,12 @@
#define BRCMF_FIL_ACTION_FRAME_SIZE 1800 #define BRCMF_FIL_ACTION_FRAME_SIZE 1800
/* ARP Offload feature flags for arp_ol iovar */
#define BRCMF_ARP_OL_AGENT 0x00000001
#define BRCMF_ARP_OL_SNOOP 0x00000002
#define BRCMF_ARP_OL_HOST_AUTO_REPLY 0x00000004
#define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008
enum brcmf_fil_p2p_if_types { enum brcmf_fil_p2p_if_types {
BRCMF_FIL_P2P_IF_CLIENT, BRCMF_FIL_P2P_IF_CLIENT,

View File

@ -47,6 +47,7 @@
#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
(channel == SOCIAL_CHAN_2) || \ (channel == SOCIAL_CHAN_2) || \
(channel == SOCIAL_CHAN_3)) (channel == SOCIAL_CHAN_3))
#define BRCMF_P2P_TEMP_CHAN SOCIAL_CHAN_3
#define SOCIAL_CHAN_CNT 3 #define SOCIAL_CHAN_CNT 3
#define AF_PEER_SEARCH_CNT 2 #define AF_PEER_SEARCH_CNT 2
@ -1954,21 +1955,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
if (err < 0) { if (err < 0) {
brcmf_err("set p2p_disc error\n"); brcmf_err("set p2p_disc error\n");
brcmf_free_vif(p2p_vif); brcmf_free_vif(cfg, p2p_vif);
goto exit; goto exit;
} }
/* obtain bsscfg index for P2P discovery */ /* obtain bsscfg index for P2P discovery */
err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
if (err < 0) { if (err < 0) {
brcmf_err("retrieving discover bsscfg index failed\n"); brcmf_err("retrieving discover bsscfg index failed\n");
brcmf_free_vif(p2p_vif); brcmf_free_vif(cfg, p2p_vif);
goto exit; goto exit;
} }
/* Verify that firmware uses same bssidx as driver !! */ /* Verify that firmware uses same bssidx as driver !! */
if (p2p_ifp->bssidx != bssidx) { if (p2p_ifp->bssidx != bssidx) {
brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
bssidx, p2p_ifp->bssidx); bssidx, p2p_ifp->bssidx);
brcmf_free_vif(p2p_vif); brcmf_free_vif(cfg, p2p_vif);
goto exit; goto exit;
} }
@ -1996,7 +1997,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_cancel_remain_on_channel(vif->ifp);
brcmf_p2p_deinit_discovery(p2p); brcmf_p2p_deinit_discovery(p2p);
/* remove discovery interface */ /* remove discovery interface */
brcmf_free_vif(vif); brcmf_free_vif(p2p->cfg, vif);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
} }
/* just set it all to zero */ /* just set it all to zero */
@ -2013,17 +2014,30 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
u16 *chanspec) u16 *chanspec)
{ {
struct brcmf_if *ifp; struct brcmf_if *ifp;
struct brcmf_fil_chan_info_le ci; u8 mac_addr[ETH_ALEN];
struct brcmu_chan ch; struct brcmu_chan ch;
s32 err; struct brcmf_bss_info_le *bi;
u8 *buf;
ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
ch.chnum = 11; if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mac_addr,
ETH_ALEN) == 0) {
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
if (!err) if (buf != NULL) {
ch.chnum = le32_to_cpu(ci.hw_channel); *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
buf, WL_BSS_INFO_MAX) == 0) {
bi = (struct brcmf_bss_info_le *)(buf + 4);
*chanspec = le16_to_cpu(bi->chanspec);
kfree(buf);
return;
}
kfree(buf);
}
}
/* Use default channel for P2P */
ch.chnum = BRCMF_P2P_TEMP_CHAN;
ch.bw = BRCMU_CHAN_BW_20; ch.bw = BRCMU_CHAN_BW_20;
p2p->cfg->d11inf.encchspec(&ch); p2p->cfg->d11inf.encchspec(&ch);
*chanspec = ch.chspec; *chanspec = ch.chspec;
@ -2208,7 +2222,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
return &p2p_vif->wdev; return &p2p_vif->wdev;
fail: fail:
brcmf_free_vif(p2p_vif); brcmf_free_vif(p2p->cfg, p2p_vif);
return ERR_PTR(err); return ERR_PTR(err);
} }
@ -2217,13 +2231,31 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
* *
* @vif: virtual interface object to delete. * @vif: virtual interface object to delete.
*/ */
static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif) static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif)
{ {
struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p;
cfg80211_unregister_wdev(&vif->wdev); cfg80211_unregister_wdev(&vif->wdev);
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
brcmf_free_vif(vif); brcmf_free_vif(cfg, vif);
}
/**
* brcmf_p2p_free_p2p_if() - free up net device related data.
*
* @ndev: net device that needs to be freed.
*/
static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
{
struct brcmf_cfg80211_info *cfg;
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
ifp = netdev_priv(ndev);
cfg = ifp->drvr->config;
vif = ifp->vif;
brcmf_free_vif(cfg, vif);
free_netdev(ifp->ndev);
} }
/** /**
@ -2303,6 +2335,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
brcmf_err("Registering netdevice failed\n"); brcmf_err("Registering netdevice failed\n");
goto fail; goto fail;
} }
/* override destructor */
ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
/* Disable firmware roaming for P2P interface */ /* Disable firmware roaming for P2P interface */
brcmf_fil_iovar_int_set(ifp, "roam_off", 1); brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
@ -2314,7 +2349,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
return &ifp->vif->wdev; return &ifp->vif->wdev;
fail: fail:
brcmf_free_vif(vif); brcmf_free_vif(cfg, vif);
return ERR_PTR(err); return ERR_PTR(err);
} }
@ -2350,7 +2385,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
break; break;
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
brcmf_p2p_delete_p2pdev(vif); brcmf_p2p_delete_p2pdev(cfg, vif);
return 0; return 0;
default: default:
return -ENOTSUPP; return -ENOTSUPP;
@ -2378,7 +2413,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
err = 0; err = 0;
} }
brcmf_cfg80211_arm_vif_event(cfg, NULL); brcmf_cfg80211_arm_vif_event(cfg, NULL);
brcmf_free_vif(vif);
p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
return err; return err;

View File

@ -459,6 +459,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
return err; return err;
} }
static s32
brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
{
s32 err;
u32 mode;
if (enable)
mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
else
mode = 0;
/* Try to set and enable ARP offload feature, this may fail, then it */
/* is simply not supported and err 0 will be returned */
err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
if (err) {
brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
mode, err);
err = 0;
} else {
err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
if (err) {
brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
enable, err);
err = 0;
} else
brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
enable, mode);
}
return err;
}
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
const char *name, const char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
@ -2216,6 +2248,11 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
} }
pm = enabled ? PM_FAST : PM_OFF; pm = enabled ? PM_FAST : PM_OFF;
/* Do not enable the power save after assoc if it is a p2p interface */
if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
pm = PM_OFF;
}
brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled")); brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
@ -3639,11 +3676,29 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
return err; return err;
} }
static s32
brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp,
struct ieee80211_channel *channel)
{
u16 chanspec;
s32 err;
brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
channel->center_freq);
chanspec = channel_to_chanspec(&cfg->d11inf, channel);
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
return err;
}
static s32 static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_ap_settings *settings) struct cfg80211_ap_settings *settings)
{ {
s32 ie_offset; s32 ie_offset;
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_tlv *ssid_ie; struct brcmf_tlv *ssid_ie;
struct brcmf_ssid_le ssid_le; struct brcmf_ssid_le ssid_le;
@ -3683,6 +3738,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
} }
brcmf_set_mpc(ifp, 0); brcmf_set_mpc(ifp, 0);
brcmf_configure_arp_offload(ifp, false);
/* find the RSN_IE */ /* find the RSN_IE */
rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@ -3713,6 +3769,12 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
if (err < 0) {
brcmf_err("Set Channel failed, %d\n", err);
goto exit;
}
if (settings->beacon_interval) { if (settings->beacon_interval) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
settings->beacon_interval); settings->beacon_interval);
@ -3789,8 +3851,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
exit: exit:
if (err) if (err) {
brcmf_set_mpc(ifp, 1); brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_offload(ifp, true);
}
return err; return err;
} }
@ -3831,6 +3895,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
brcmf_err("bss_enable config failed %d\n", err); brcmf_err("bss_enable config failed %d\n", err);
} }
brcmf_set_mpc(ifp, 1); brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_offload(ifp, true);
set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
@ -4148,7 +4213,7 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
static const struct ieee80211_iface_combination brcmf_iface_combos[] = { static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
{ {
.max_interfaces = BRCMF_IFACE_MAX_CNT, .max_interfaces = BRCMF_IFACE_MAX_CNT,
.num_different_channels = 1, /* no multi-channel for now */ .num_different_channels = 2,
.n_limits = ARRAY_SIZE(brcmf_iface_limits), .n_limits = ARRAY_SIZE(brcmf_iface_limits),
.limits = brcmf_iface_limits .limits = brcmf_iface_limits
} }
@ -4256,20 +4321,16 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
return vif; return vif;
} }
void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif)
{ {
struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
wiphy = vif->wdev.wiphy;
cfg = wiphy_priv(wiphy);
list_del(&vif->list); list_del(&vif->list);
cfg->vif_cnt--; cfg->vif_cnt--;
kfree(vif); kfree(vif);
if (!cfg->vif_cnt) { if (!cfg->vif_cnt) {
wiphy_unregister(wiphy); wiphy_unregister(cfg->wiphy);
wiphy_free(wiphy); wiphy_free(cfg->wiphy);
} }
} }
@ -4646,7 +4707,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
return 0; return 0;
case BRCMF_E_IF_DEL: case BRCMF_E_IF_DEL:
ifp->vif = NULL;
mutex_unlock(&event->vif_event_lock); mutex_unlock(&event->vif_event_lock);
/* event may not be upon user request */ /* event may not be upon user request */
if (brcmf_cfg80211_vif_event_armed(cfg)) if (brcmf_cfg80211_vif_event_armed(cfg))
@ -4852,8 +4912,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
wl_deinit_priv(cfg); wl_deinit_priv(cfg);
cfg80211_attach_out: cfg80211_attach_out:
brcmf_free_vif(vif); brcmf_free_vif(cfg, vif);
wiphy_free(wiphy);
return NULL; return NULL;
} }
@ -4865,7 +4924,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
wl_deinit_priv(cfg); wl_deinit_priv(cfg);
brcmf_btcoex_detach(cfg); brcmf_btcoex_detach(cfg);
list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
brcmf_free_vif(vif); brcmf_free_vif(cfg, vif);
} }
} }
@ -5229,6 +5288,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
if (err) if (err)
goto default_conf_out; goto default_conf_out;
brcmf_configure_arp_offload(ifp, true);
cfg->dongle_up = true; cfg->dongle_up = true;
default_conf_out: default_conf_out:

View File

@ -487,7 +487,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type, enum nl80211_iftype type,
bool pm_block); bool pm_block);
void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len); const u8 *vndr_ie_buf, u32 vndr_ie_len);

View File

@ -735,7 +735,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
memcpy(&lq, priv->stations[i].lq, memcpy(&lq, priv->stations[i].lq,
sizeof(struct iwl_link_quality_cmd)); sizeof(struct iwl_link_quality_cmd));
if (!memcmp(&lq, &zero_lq, sizeof(lq))) if (memcmp(&lq, &zero_lq, sizeof(lq)))
send_lq = true; send_lq = true;
} }
spin_unlock_bh(&priv->sta_lock); spin_unlock_bh(&priv->sta_lock);

View File

@ -28,7 +28,7 @@ config NFC_WILINK
config NFC_MEI_PHY config NFC_MEI_PHY
tristate "MEI bus NFC device support" tristate "MEI bus NFC device support"
depends on INTEL_MEI_BUS_NFC && NFC_HCI depends on INTEL_MEI && NFC_HCI
help help
This adds support to use an mei bus nfc device. Select this if you This adds support to use an mei bus nfc device. Select this if you
will use an HCI NFC driver for an NFC chip connected behind an will use an HCI NFC driver for an NFC chip connected behind an

View File

@ -64,6 +64,15 @@ int nfc_mei_phy_enable(void *phy_id)
return r; return r;
} }
r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
if (r) {
pr_err("MEY_PHY: Event cb registration failed\n");
mei_cl_disable_device(phy->device);
phy->powered = 0;
return r;
}
phy->powered = 1; phy->powered = 1;
return 0; return 0;

View File

@ -43,24 +43,16 @@ static int microread_mei_probe(struct mei_cl_device *device,
return -ENOMEM; return -ENOMEM;
} }
r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
if (r) {
pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
goto err_out;
}
r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
&phy->hdev); &phy->hdev);
if (r < 0) if (r < 0) {
goto err_out; nfc_mei_phy_free(phy);
return r;
}
return 0; return 0;
err_out:
nfc_mei_phy_free(phy);
return r;
} }
static int microread_mei_remove(struct mei_cl_device *device) static int microread_mei_remove(struct mei_cl_device *device)
@ -71,8 +63,6 @@ static int microread_mei_remove(struct mei_cl_device *device)
microread_remove(phy->hdev); microread_remove(phy->hdev);
nfc_mei_phy_disable(phy);
nfc_mei_phy_free(phy); nfc_mei_phy_free(phy);
return 0; return 0;

View File

@ -43,24 +43,16 @@ static int pn544_mei_probe(struct mei_cl_device *device,
return -ENOMEM; return -ENOMEM;
} }
r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
if (r) {
pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
goto err_out;
}
r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME, r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
&phy->hdev); &phy->hdev);
if (r < 0) if (r < 0) {
goto err_out; nfc_mei_phy_free(phy);
return r;
}
return 0; return 0;
err_out:
nfc_mei_phy_free(phy);
return r;
} }
static int pn544_mei_remove(struct mei_cl_device *device) static int pn544_mei_remove(struct mei_cl_device *device)
@ -71,8 +63,6 @@ static int pn544_mei_remove(struct mei_cl_device *device)
pn544_hci_remove(phy->hdev); pn544_hci_remove(phy->hdev);
nfc_mei_phy_disable(phy);
nfc_mei_phy_free(phy); nfc_mei_phy_free(phy);
return 0; return 0;

View File

@ -159,9 +159,10 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *iter;
u64 new, mask, tmp; u64 new, mask, tmp;
u8 *m; u8 *m;
int ret = 0; int ret = 0;
@ -181,11 +182,14 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(iter, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) if (iter == sdata)
continue; continue;
m = sdata->vif.addr; if (iter->vif.type == NL80211_IFTYPE_MONITOR)
continue;
m = iter->vif.addr;
tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
@ -209,7 +213,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
if (ieee80211_sdata_running(sdata)) if (ieee80211_sdata_running(sdata))
return -EBUSY; return -EBUSY;
ret = ieee80211_verify_mac(sdata->local, sa->sa_data); ret = ieee80211_verify_mac(sdata, sa->sa_data);
if (ret) if (ret)
return ret; return ret;
@ -474,6 +478,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
master->control_port_protocol; master->control_port_protocol;
sdata->control_port_no_encrypt = sdata->control_port_no_encrypt =
master->control_port_no_encrypt; master->control_port_no_encrypt;
sdata->vif.cab_queue = master->vif.cab_queue;
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
sizeof(sdata->vif.hw_queue));
break; break;
} }
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
@ -653,7 +660,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local, -1);
if (dev) { if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
/* XXX: for AP_VLAN, actually track AP queues */
netif_tx_start_all_queues(dev);
} else if (dev) {
unsigned long flags; unsigned long flags;
int n_acs = IEEE80211_NUM_ACS; int n_acs = IEEE80211_NUM_ACS;
int ac; int ac;
@ -1479,7 +1490,17 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
break; break;
} }
/*
* Pick address of existing interface in case user changed
* MAC address manually, default to perm_addr.
*/
m = local->hw.wiphy->perm_addr; m = local->hw.wiphy->perm_addr;
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
m = sdata->vif.addr;
break;
}
start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
@ -1696,6 +1717,15 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
ASSERT_RTNL(); ASSERT_RTNL();
/*
* Close all AP_VLAN interfaces first, as otherwise they
* might be closed while the AP interface they belong to
* is closed, causing unregister_netdevice_many() to crash.
*/
list_for_each_entry(sdata, &local->interfaces, list)
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
dev_close(sdata->dev);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
list_del(&sdata->list); list_del(&sdata->list);

View File

@ -3321,10 +3321,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
if (WARN_ON_ONCE(!auth_data)) if (WARN_ON_ONCE(!auth_data))
return -EINVAL; return -EINVAL;
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
auth_data->tries++; auth_data->tries++;
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
@ -3358,6 +3354,10 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
auth_data->expected_transaction = trans; auth_data->expected_transaction = trans;
} }
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len, auth_data->data, auth_data->data_len,
auth_data->bss->bssid, auth_data->bss->bssid,
@ -3381,12 +3381,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
* will not answer to direct packet in unassociated state. * will not answer to direct packet in unassociated state.
*/ */
ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
NULL, 0, (u32) -1, true, tx_flags, NULL, 0, (u32) -1, true, 0,
auth_data->bss->channel, false); auth_data->bss->channel, false);
rcu_read_unlock(); rcu_read_unlock();
} }
if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { if (tx_flags == 0) {
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
ifmgd->auth_data->timeout_started = true; ifmgd->auth_data->timeout_started = true;
run_again(ifmgd, auth_data->timeout); run_again(ifmgd, auth_data->timeout);

View File

@ -5,7 +5,6 @@
obj-$(CONFIG_NFC) += nfc.o obj-$(CONFIG_NFC) += nfc.o
obj-$(CONFIG_NFC_NCI) += nci/ obj-$(CONFIG_NFC_NCI) += nci/
obj-$(CONFIG_NFC_HCI) += hci/ obj-$(CONFIG_NFC_HCI) += hci/
#obj-$(CONFIG_NFC_LLCP) += llcp/
nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \ nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \
llcp_sock.o llcp_sock.o

View File

@ -3411,7 +3411,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
(u32)sinfo->rx_bytes)) (u32)sinfo->rx_bytes))
goto nla_put_failure; goto nla_put_failure;
if ((sinfo->filled & (STATION_INFO_TX_BYTES | if ((sinfo->filled & (STATION_INFO_TX_BYTES |
NL80211_STA_INFO_TX_BYTES64)) && STATION_INFO_TX_BYTES64)) &&
nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
(u32)sinfo->tx_bytes)) (u32)sinfo->tx_bytes))
goto nla_put_failure; goto nla_put_failure;

View File

@ -231,6 +231,9 @@ void cfg80211_conn_work(struct work_struct *work)
mutex_lock(&rdev->sched_scan_mtx); mutex_lock(&rdev->sched_scan_mtx);
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->netdev)
continue;
wdev_lock(wdev); wdev_lock(wdev);
if (!netif_running(wdev->netdev)) { if (!netif_running(wdev->netdev)) {
wdev_unlock(wdev); wdev_unlock(wdev);