Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/linville/wireless-next-2.6 into for-davem
  • Loading branch information
linvjw committed Mar 15, 2011
2 parents 0c0217b + 7d2c16b commit 106af2c
Show file tree
Hide file tree
Showing 31 changed files with 596 additions and 244 deletions.
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath5k/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
spin_lock_init(&txq->lock);
txq->setup = true;
txq->txq_len = 0;
txq->txq_max = ATH5K_TXQ_LEN_MAX;
txq->txq_poll_mark = false;
txq->txq_stuck = 0;
}
Expand Down Expand Up @@ -1534,7 +1535,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
goto drop_packet;
}

if (txq->txq_len >= ATH5K_TXQ_LEN_MAX)
if (txq->txq_len >= txq->txq_max)
ieee80211_stop_queue(hw, txq->qnum);

spin_lock_irqsave(&sc->txbuflock, flags);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/ath/ath5k/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct ath5k_txq {
spinlock_t lock; /* lock on q and link */
bool setup;
int txq_len; /* number of queued buffers */
int txq_max; /* max allowed num of queued buffers */
bool txq_poll_mark;
unsigned int txq_stuck; /* informational counter */
};
Expand Down
43 changes: 43 additions & 0 deletions drivers/net/wireless/ath/ath5k/mac80211-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,47 @@ ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
}


static void ath5k_get_ringparam(struct ieee80211_hw *hw,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
{
struct ath5k_softc *sc = hw->priv;

*tx = sc->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max;

*tx_max = ATH5K_TXQ_LEN_MAX;
*rx = *rx_max = ATH_RXBUF;
}


static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx)
{
struct ath5k_softc *sc = hw->priv;
u16 qnum;

/* only support setting tx ring size for now */
if (rx != ATH_RXBUF)
return -EINVAL;

/* restrict tx ring size min/max */
if (!tx || tx > ATH5K_TXQ_LEN_MAX)
return -EINVAL;

for (qnum = 0; qnum < ARRAY_SIZE(sc->txqs); qnum++) {
if (!sc->txqs[qnum].setup)
continue;
if (sc->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN ||
sc->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX)
continue;

sc->txqs[qnum].txq_max = tx;
if (sc->txqs[qnum].txq_len >= sc->txqs[qnum].txq_max)
ieee80211_stop_queue(hw, sc->txqs[qnum].qnum);
}

return 0;
}


const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
.start = ath5k_start,
Expand Down Expand Up @@ -778,4 +819,6 @@ const struct ieee80211_ops ath5k_hw_ops = {
/* .napi_poll = not implemented */
.set_antenna = ath5k_set_antenna,
.get_antenna = ath5k_get_antenna,
.set_ringparam = ath5k_set_ringparam,
.get_ringparam = ath5k_get_ringparam,
};
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath9k/ar9485_initvals.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = {

static const u32 ar9485_1_0_soc_preamble[][2] = {
/* Addr allmodes */
{0x00004090, 0x00aa10aa},
{0x000040a4, 0x00a0c9c9},
{0x00007048, 0x00000004},
};
Expand Down Expand Up @@ -1708,6 +1709,7 @@ static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
static const u32 ar9485_1_1_soc_preamble[][2] = {
/* Addr allmodes */
{0x00004014, 0xba280400},
{0x00004090, 0x00aa10aa},
{0x000040a4, 0x00a0c9c9},
{0x00007010, 0x00000022},
{0x00007020, 0x00000000},
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ struct ath_txq {
u32 axq_ampdu_depth;
bool stopped;
bool axq_tx_inprogress;
bool txq_flush_inprogress;
struct list_head axq_acq;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
struct list_head txq_fifo_pending;
Expand Down
13 changes: 2 additions & 11 deletions drivers/net/wireless/ath/ath9k/beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ void ath_beacon_tasklet(unsigned long data)
ath_dbg(common, ATH_DBG_BSTUCK,
"missed %u consecutive beacons\n",
sc->beacon.bmisscnt);
ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
ath9k_hw_bstuck_nfcal(ah);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
ath_dbg(common, ATH_DBG_BSTUCK,
Expand Down Expand Up @@ -450,16 +451,6 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.updateslot = OK;
}
if (bfaddr != 0) {
/*
* Stop any current dma and put the new frame(s) on the queue.
* This should never fail since we check above that no frames
* are still pending on the queue.
*/
if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
ath_err(common, "beacon queue %u did not stop?\n",
sc->beacon.beaconq);
}

/* NB: cabq traffic should already be queued and primed */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
ath9k_hw_txstart(ah, sc->beacon.beaconq);
Expand Down Expand Up @@ -780,7 +771,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
ah->imask &= ~ATH9K_INT_SWBA;
ath9k_hw_set_interrupts(ah, ah->imask);
tasklet_kill(&sc->bcon_tasklet);
ath9k_hw_stoptxdma(ah, sc->beacon.beaconq);
ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
}
ath9k_ps_restore(sc);
}
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath9k/calib.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
* since 250us often results in NF load timeout and causes deaf
* condition during stress testing 12/12/2009
*/
for (j = 0; j < 1000; j++) {
for (j = 0; j < 10000; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
Expand All @@ -278,7 +278,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
* here, the baseband nf cal will just be capped by our present
* noisefloor until the next calibration timer.
*/
if (j == 1000) {
if (j == 10000) {
ath_dbg(common, ATH_DBG_ANY,
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath9k/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);

REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
udelay(100);
udelay(1000);

REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);

Expand All @@ -713,7 +713,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
udelay(110);
udelay(1000);
}

pll = ath9k_hw_compute_pll_control(ah, chan);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath9k/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@
#define REG_READ_FIELD(_a, _r, _f) \
(((REG_READ(_a, _r) & _f) >> _f##_S))
#define REG_SET_BIT(_a, _r, _f) \
REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f))
#define REG_CLR_BIT(_a, _r, _f) \
REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f))

#define DO_DELAY(x) do { \
if ((++(x) % 64) == 0) \
Expand Down
89 changes: 32 additions & 57 deletions drivers/net/wireless/ath/ath9k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,84 +143,59 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
}
EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);

bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
{
#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
#define ATH9K_TIME_QUANTUM 100 /* usec */
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
u32 tsfLow, j, wait;
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
int i, q;

if (q >= pCap->total_queues) {
ath_dbg(common, ATH_DBG_QUEUE,
"Stopping TX DMA, invalid queue: %u\n", q);
return false;
}
REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);

qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
ath_dbg(common, ATH_DBG_QUEUE,
"Stopping TX DMA, inactive queue: %u\n", q);
return false;
}
REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);

REG_WRITE(ah, AR_Q_TXD, 1 << q);
for (q = 0; q < AR_NUM_QCU; q++) {
for (i = 0; i < 1000; i++) {
if (i)
udelay(5);

for (wait = wait_time; wait != 0; wait--) {
if (ath9k_hw_numtxpending(ah, q) == 0)
break;
udelay(ATH9K_TIME_QUANTUM);
if (!ath9k_hw_numtxpending(ah, q))
break;
}
}

if (ath9k_hw_numtxpending(ah, q)) {
ath_dbg(common, ATH_DBG_QUEUE,
"%s: Num of pending TX Frames %d on Q %d\n",
__func__, ath9k_hw_numtxpending(ah, q), q);

for (j = 0; j < 2; j++) {
tsfLow = REG_READ(ah, AR_TSF_L32);
REG_WRITE(ah, AR_QUIET2,
SM(10, AR_QUIET2_QUIET_DUR));
REG_WRITE(ah, AR_QUIET_PERIOD, 100);
REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
REG_SET_BIT(ah, AR_TIMER_MODE,
AR_QUIET_TIMER_EN);

if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
break;
REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);

ath_dbg(common, ATH_DBG_QUEUE,
"TSF has moved while trying to set quiet time TSF: 0x%08x\n",
tsfLow);
}
REG_WRITE(ah, AR_Q_TXD, 0);
}
EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);

REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
{
#define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */
#define ATH9K_TIME_QUANTUM 100 /* usec */
int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
int wait;

udelay(200);
REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
REG_WRITE(ah, AR_Q_TXD, 1 << q);

wait = wait_time;
while (ath9k_hw_numtxpending(ah, q)) {
if ((--wait) == 0) {
ath_err(common,
"Failed to stop TX DMA in 100 msec after killing last frame\n");
break;
}
for (wait = wait_time; wait != 0; wait--) {
if (wait != wait_time)
udelay(ATH9K_TIME_QUANTUM);
}

REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
if (ath9k_hw_numtxpending(ah, q) == 0)
break;
}

REG_WRITE(ah, AR_Q_TXD, 0);

return wait != 0;

#undef ATH9K_TX_STOP_DMA_TIMEOUT
#undef ATH9K_TIME_QUANTUM
}
EXPORT_SYMBOL(ath9k_hw_stoptxdma);
EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);

void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
{
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath9k/mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,8 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
const struct ath9k_tx_queue_info *qinfo);
Expand Down
56 changes: 21 additions & 35 deletions drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,56 +2128,42 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)

static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
{
#define ATH_FLUSH_TIMEOUT 60 /* ms */
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = NULL;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int i, j, npend = 0;
int timeout = 200; /* ms */
int i, j;

ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex);

cancel_delayed_work_sync(&sc->tx_complete_work);

for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;
txq = &sc->tx.txq[i];
if (drop)
timeout = 1;

if (!drop) {
for (j = 0; j < ATH_FLUSH_TIMEOUT; j++) {
if (!ath9k_has_pending_frames(sc, txq))
break;
usleep_range(1000, 2000);
}
}
for (j = 0; j < timeout; j++) {
int npend = 0;

if (j)
usleep_range(1000, 2000);

if (drop || ath9k_has_pending_frames(sc, txq)) {
ath_dbg(common, ATH_DBG_QUEUE, "Drop frames from hw queue:%d\n",
txq->axq_qnum);
spin_lock_bh(&txq->axq_lock);
txq->txq_flush_inprogress = true;
spin_unlock_bh(&txq->axq_lock);

ath9k_ps_wakeup(sc);
ath9k_hw_stoptxdma(ah, txq->axq_qnum);
npend = ath9k_hw_numtxpending(ah, txq->axq_qnum);
ath9k_ps_restore(sc);
if (npend)
break;

ath_draintxq(sc, txq, false);
txq->txq_flush_inprogress = false;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;

npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
}

if (!npend)
goto out;
}

if (npend) {
if (!ath_drain_all_txq(sc, false))
ath_reset(sc, false);
txq->txq_flush_inprogress = false;
}

out:
ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc);
}

struct ieee80211_ops ath9k_ops = {
Expand Down
Loading

0 comments on commit 106af2c

Please sign in to comment.