[ath5k-devel] [PATCH 01/13] ath5k: Switch from read-and-clear to write-to-clear method when handling PISR/SISR registers
Since card has 12 tx queues and we want to keep track of the interrupts per queue we can't fit all these interrupt bits on a single register. So we have 5 registers, the primary interrupt status register (PISR) and the 4 secondary interupt status registers (SISRs). In order to be able to read them all at once (atomic operation) Atheros introduced the Read-And-Clear registers to make things easier. So when reading RAC_PISR register, hw does a read on PISR and all SISRs, returns the value of PISR, copies all SISR values to their shadow copies (RAC_SISRx) and clears PISR and SISRs. This saves us from reading PISR/SISRs in a sequence. So far we 've used this approach and MadWiFi/Windows driver etc also used it for years. It turns out this operation is not atomic after all (at least not on all cards) That means it's possible to loose some interrupts because they came after the copy step and hw cleared them on the clean step ! That's probably the reason we got missed beacons, got stuck queues etc and couldn't figure out what was going on. With this patch we switch from RaC operation to an alternative method (that makes more sense IMHO anyway, I just chose to be on the safe side so far). Instead of reading RAC registers, we read the normal PISR/SISR registers and clear any bits we got by writing them back on the register. This will clear only the bits we got on our read step and leave any new bits unaffected (at least that's what docs say). So if any new interrupts come up we won't miss it. I've tested this with an AR5213 and an AR2425 and it seems O.K. Many thanks to Adrian Chadd for debuging this ! Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ath5k.h |8 +- drivers/net/wireless/ath/ath5k/base.c |2 +- drivers/net/wireless/ath/ath5k/dma.c | 206 +++- drivers/net/wireless/ath/ath5k/reg.h |9 +- 4 files changed, 134 insertions(+), 91 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fecbcd9..0f42a57 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1187,7 +1187,13 @@ struct ath5k_hw { u32 ah_txq_imr_cbrurn; u32 ah_txq_imr_qtrig; u32 ah_txq_imr_nofrm; - u32 ah_txq_isr; + + u32 ah_txq_isr_txok_all; + u32 ah_txq_isr_txurn; + u32 ah_txq_isr_qcborn; + u32 ah_txq_isr_qcburn; + u32 ah_txq_isr_qtrig; + u32 *ah_rf_banks; size_t ah_rf_banks_size; size_t ah_rf_regs_count; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index b346d04..c18d310 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1689,7 +1689,7 @@ ath5k_tasklet_tx(unsigned long data) struct ath5k_hw *ah = (void *)data; for (i = 0; i AR5K_NUM_TX_QUEUES; i++) - if (ah-txqs[i].setup (ah-ah_txq_isr BIT(i))) + if (ah-txqs[i].setup (ah-ah_txq_isr_txok_all BIT(i))) ath5k_tx_processq(ah, ah-txqs[i]); ah-tx_pending = false; diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 2481f9c..3a14475 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -450,7 +450,6 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) * * XXX: Link this with tx DMA size ? * XXX: Use it to save interrupts ? - * TODO: Needs testing, i think it's related to bmiss... */ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) { @@ -523,62 +522,122 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * being mapped on some standard non hw-specific positions * (check out ath5k_int). * - * NOTE: We use read-and-clear register, so after this function is called ISR - * is zeroed. + * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this + * function gets called are cleared on return. */ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { - u32 data; + u32 data = 0; /* -* Read interrupt status from the Interrupt Status register -* on 5210 +* Read interrupt status from Primary Interrupt +* Register. +* +* Note: PISR/SISR Not available on 5210 */ if (ah-ah_version == AR5K_AR5210) { - data = ath5k_hw_reg_read(ah, AR5K_ISR); - if (unlikely(data == AR5K_INT_NOCARD)) { - *interrupt_mask = data; + u32 isr = 0; + isr = ath5k_hw_reg_read(ah, AR5K_ISR); + if
[ath5k-devel] [PATCH 05/13] ath5k: Calibration re-work
Noise floor calibration does not interfere with traffic and should run more often as part of our short calibration. The full calibration is not the noise floor calibration but the AGC + Gain_F (on RF5111 and RF5112) calibration and should run less often because it does interfere with traffic. So Short calibration - I/Q NF Calibration Long calibration - Short + AGC + Gain_F This patch was for some time on my pub/ dir on www.kernel.org and has been tested by a few people and me. I think it's O.K. to go in. I also changed ah_calibration to ah_iq_cal_needed to make more sense. Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ath5k.h | 12 ++-- drivers/net/wireless/ath/ath5k/base.c | 102 +++- drivers/net/wireless/ath/ath5k/phy.c | 81 +++-- 3 files changed, 140 insertions(+), 55 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index b8abdbc..5f9362d 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -187,10 +187,9 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL1 /* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL6 /* 60 sec */ +#defineATH5K_TUNE_CALIBRATION_INTERVAL_SHORT 1 /* 10 sec */ #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI1000/* 1 sec */ -#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 6 /* 60 sec */ - #define ATH5K_TX_COMPLETE_POLL_INT 3000/* 3 sec */ #define AR5K_INIT_CARR_SENSE_EN1 @@ -896,7 +895,8 @@ enum ath5k_int { enum ath5k_calibration_mask { AR5K_CALIBRATION_FULL = 0x01, AR5K_CALIBRATION_SHORT = 0x02, - AR5K_CALIBRATION_ANI = 0x04, + AR5K_CALIBRATION_NF = 0x04, + AR5K_CALIBRATION_ANI = 0x08, }; /* @@ -1145,7 +1145,7 @@ struct ath5k_hw { enum ath5k_int ah_imr; struct ieee80211_channel *ah_current_channel; - boolah_calibration; + boolah_iq_cal_needed; boolah_single_chip; enum ath5k_version ah_version; @@ -1235,8 +1235,8 @@ struct ath5k_hw { /* Calibration timestamp */ unsigned long ah_cal_next_full; + unsigned long ah_cal_next_short; unsigned long ah_cal_next_ani; - unsigned long ah_cal_next_nf; /* Calibration mask */ u8 ah_cal_mask; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 47194a4..120bba0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2112,15 +2112,28 @@ static void ath5k_intr_calibration_poll(struct ath5k_hw *ah) { if (time_is_before_eq_jiffies(ah-ah_cal_next_ani) - !(ah-ah_cal_mask AR5K_CALIBRATION_FULL)) { - /* run ANI only when full calibration is not active */ + !(ah-ah_cal_mask AR5K_CALIBRATION_FULL) + !(ah-ah_cal_mask AR5K_CALIBRATION_SHORT)) { + + /* Run ANI only when calibration is not active */ + ah-ah_cal_next_ani = jiffies + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); tasklet_schedule(ah-ani_tasklet); - } else if (time_is_before_eq_jiffies(ah-ah_cal_next_full)) { - ah-ah_cal_next_full = jiffies + - msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); + } else if (time_is_before_eq_jiffies(ah-ah_cal_next_short) + !(ah-ah_cal_mask AR5K_CALIBRATION_FULL) + !(ah-ah_cal_mask AR5K_CALIBRATION_SHORT)) { + + /* Run calibration only when another calibration +* is not running. +* +* Note: This is for both full/short calibration, +* if it's time for a full one, tasklet will deal +* with it. */ + + ah-ah_cal_next_short = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); tasklet_schedule(ah-calib); } /* we could use SWI to generate enough interrupts to meet our @@ -2290,37 +2303,53 @@ ath5k_tasklet_calibrate(unsigned long data) { struct ath5k_hw *ah = (void *)data; - /* Only full calibration for now */ - ah-ah_cal_mask |= AR5K_CALIBRATION_FULL; + /* Should we run a full calibration ? */ + if (time_is_before_eq_jiffies(ah-ah_cal_next_full)) { + + ah-ah_cal_next_full = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); + ah-ah_cal_mask |= AR5K_CALIBRATION_FULL; +
[ath5k-devel] [PATCH 02/13] ath5k: Maintain PISR snapshot
Since we dont read a snapshot of the interrupt registers it might be possible to get a new interrupt while reading them. In this case we should make sure that we clear all SISR bits we get from PISR. Tested on an AR2425 Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/dma.c | 49 - drivers/net/wireless/ath/ath5k/reg.h | 12 +++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 3a14475..6a7b907 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -578,16 +578,59 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) return -ENODEV; } + /* Sanity checks: +* Since we read these registers sequentialy +* we might get a new interrupt while reading +* e.g. SISR0 that we didn't catch when reading +* PISR. So since we are going to handle it on +* this run of get_isr, we need to clear it +* from PISR also (PISR contains the logical OR of +* various interrupt bits from SISRs -see reg.h). +* +* NOTE: We could check if PISR is inconsistent +* with SISRs but it 'll take more time for no +* reason. If e.g. a TXOK bit is set on SISR0 +* it 'll also get set on PISR by hw anyway. */ + sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0); + if (sisr0 AR5K_SISR0_QCU_TXOK) + pisr |= AR5K_ISR_TXOK; + if (sisr0 AR5K_SISR0_QCU_TXDESC) + pisr |= AR5K_ISR_TXDESC; + sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1); + if (sisr1 AR5K_SISR1_QCU_TXERR) + pisr |= AR5K_ISR_TXERR; + if (sisr1 AR5K_SISR1_QCU_TXEOL) + pisr |= AR5K_ISR_TXEOL; + sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2); + if (sisr2 AR5K_SISR2_QCU_TXURN) + pisr |= AR5K_ISR_TXURN; + if (sisr2 (AR5K_SISR2_MCABT | AR5K_SISR2_SSERR + | AR5K_SISR2_DPERR)) + pisr |= AR5K_ISR_HIUERR; + if (sisr2 (AR5K_SISR2_TIM | AR5K_SISR2_CAB_END + | AR5K_SISR2_DTIM_SYNC | AR5K_SISR2_BCN_TIMEOUT + | AR5K_SISR2_CAB_TIMEOUT | AR5K_SISR2_DTIM)) + pisr |= AR5K_ISR_BCNMISC; + /* XXX: How about TSFOOR ? Docs say nothing about +* it being bart of BCNMISC, it doesn't make sense ! */ + sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3); - sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4); + if (sisr3 AR5K_SISR3_QCBRORN) + pisr |= AR5K_ISR_QCBRORN; + if (sisr3 AR5K_SISR3_QCBRURN) + pisr |= AR5K_ISR_QCBRURN; + sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4); + if (sisr4 AR5K_SISR4_QTRIG) + pisr |= AR5K_ISR_QTRIG; /* * Write to clear them... -* Note: This means that each bit we write back +* +* NOTE: This means that each bit we write back * to the registers will get cleared, leaving the * rest unaffected. So this won't affect new interrupts * we didn't catch while reading/processing, we 'll get @@ -634,9 +677,11 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) AR5K_SISR2_QCU_TXURN); /* Misc Beacon related interrupts */ + /* This one is for 5211 */ if (pisr AR5K_ISR_TIM) *interrupt_mask |= AR5K_INT_TIM; + /* For 5212+ */ if (pisr AR5K_ISR_BCNMISC) { if (sisr2 AR5K_SISR2_TIM) *interrupt_mask |= AR5K_INT_TIM; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 688d509..99bbfb4 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -280,6 +280,10 @@ * 5211/5212 we have one primary and 4 secondary registers. * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. * Most of these bits are common for all chipsets. + * + * NOTE: On 5211+ TXOK, TXDESC, TXERR, TXEOL and TXURN contain + * the logical OR from per-queue interrupt bits found on SISR registers + * (see below). */ #define AR5K_ISR 0x001c /* Register Address [5210] */ #define AR5K_PISR 0x0080 /* Register Address [5211+] */ @@ -292,7 +296,10 @@ #define
[ath5k-devel] [PATCH 13/13] ath5k: Optimize ath5k_cw_validate
Optimize ath5k_cw_validate by using the classic (X (X - 1)) == 0 check to see if a number is power of 2. Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/qcu.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index e50e64d..cdbaad7 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -111,6 +111,16 @@ ath5k_cw_validate(u16 cw_req) u32 cw = 1; cw_req = min(cw_req, (u16)1023); + /* Check if cw_req + 1 a power of 2 */ + if (!((cw_req + 1) cw_req)) + return cw_req; + + /* Check if cw_req is a power of 2 */ + if (!(cw_req (cw_req - 1))) + return cw_req - 1; + + /* If none of the above is correct +* find the closest power of 2 */ while (cw cw_req) cw = (cw 1) | 1; -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 09/13] ath5k: Add a module parameter to disable hw rf kill switch
Add a module parameter to disable hw rf kill switch (GPIO interrupt) because in some cases when the card doesn't come with the laptop, EEPROM configuration doesn't match laptop's configuration and rf kill interrupt always fires up and disables hw. I thought of moving this to debugfs and make it per-card but this way it's easier for users and distros to handle. Signed-off-by: Nick Kossifidis mickfl...@gmail.com Tested-by: Pavel Roskin pro...@.gnu.org --- drivers/net/wireless/ath/ath5k/base.c | 11 +-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 587c6fb..b901721 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -80,6 +80,11 @@ static int modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); MODULE_PARM_DESC(fastchanswitch, Enable fast channel switching for AR2413/AR5413 radios.); +static int ath5k_modparam_no_hw_rfkill_switch; +module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, + bool, S_IRUGO); +MODULE_PARM_DESC(no_hw_rfkill_switch, Ignore the GPIO RFKill switch state); + /* Module info */ MODULE_AUTHOR(Jiri Slaby); @@ -2634,7 +2639,8 @@ int ath5k_start(struct ieee80211_hw *hw) if (ret) goto done; - ath5k_rfkill_hw_start(ah); + if (!ath5k_modparam_no_hw_rfkill_switch) + ath5k_rfkill_hw_start(ah); /* * Reset the key cache since some parts do not reset the @@ -2719,7 +2725,8 @@ void ath5k_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(ah-tx_complete_work); - ath5k_rfkill_hw_stop(ah); + if (!ath5k_modparam_no_hw_rfkill_switch) + ath5k_rfkill_hw_stop(ah); } /* -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 12/13] ath5k: Renumber hw queue ids
According to documentation higher DCUs have higher priority and should be used for beacons and CAB traffic. More specifically DCU 9 should be used for beacons and DCU 8 for CAB traffic, I assumed DCU 7 should be OK for UAPSD traffic. Note that DCU 8 and 9 are special because they can only be mapped to a single QCU each but since we use a 1:1 mapping between QCUs and DCUs anyway we don't have to change much. P.S. I also did a few related cleanups on qcu.c and ath5k.h Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ath5k.h | 10 -- drivers/net/wireless/ath/ath5k/qcu.c | 14 +++--- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 304cc92..892aaa1 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -571,20 +571,18 @@ enum ath5k_tx_queue_subtype { * @AR5K_TX_QUEUE_ID_CAB: Content after beacon queue * @AR5K_TX_QUEUE_ID_BEACON: Beacon queue * @AR5K_TX_QUEUE_ID_UAPSD: Urgent Automatic Power Save Delivery, - * @AR5K_TX_QUEUE_ID_XR_DATA: XR Data queue * * Each number represents a hw queue. If hw does not support hw queues - * (eg 5210) all data goes in one queue. These match - * mac80211 definitions. + * (eg 5210) all data goes in one queue. */ enum ath5k_tx_queue_id { AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, AR5K_TX_QUEUE_ID_DATA_MIN = 0, AR5K_TX_QUEUE_ID_DATA_MAX = 3, - AR5K_TX_QUEUE_ID_CAB= 6, - AR5K_TX_QUEUE_ID_BEACON = 7, - AR5K_TX_QUEUE_ID_UAPSD = 8, + AR5K_TX_QUEUE_ID_UAPSD = 7, + AR5K_TX_QUEUE_ID_CAB= 8, + AR5K_TX_QUEUE_ID_BEACON = 9, }; /* diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 31924c3..e50e64d 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -54,7 +54,7 @@ Queue Control Unit, DCF Control Unit Functions /** * ath5k_hw_num_tx_pending() - Get number of pending frames for a given queue * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id */ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) @@ -85,7 +85,7 @@ ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) /** * ath5k_hw_release_tx_queue() - Set a transmit queue inactive * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id */ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) @@ -120,7 +120,7 @@ ath5k_cw_validate(u16 cw_req) /** * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id * @queue_info: The struct ath5k_txq_info to fill */ int @@ -134,7 +134,7 @@ ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, /** * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id * @qinfo: The struct ath5k_txq_info to use * * Returns 0 on success or -EIO if queue is inactive @@ -267,7 +267,7 @@ ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, /** * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id * * This function is used when initializing a queue, to set * retry limits based on ah-ah_retry_* and the chipset used. @@ -310,9 +310,9 @@ ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, /** * ath5k_hw_reset_tx_queue() - Initialize a single hw queue * @ah: The struct ath5k_hw - * @queue: The hw queue number + * @queue: One of enum ath5k_tx_queue_id * - * Set DFS properties for the given transmit queue on DCU + * Set DCF properties for the given transmit queue on DCU * and configures all queue-specific parameters. */ int -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 06/13] ath5k: Use usleep_range where possible
Use usleep_range where possible to reduce busy waits Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/attach.c |2 +- drivers/net/wireless/ath/ath5k/pci.c|2 +- drivers/net/wireless/ath/ath5k/phy.c| 22 +++--- drivers/net/wireless/ath/ath5k/reset.c | 14 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 91627dd..49fdc93 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -298,7 +298,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) /* Reset SERDES to load new settings */ ath5k_hw_reg_write(ah, 0x, AR5K_PCIE_SERDES_RESET); - mdelay(1); + usleep_range(1000, 1500); } /* Get misc capabilities */ diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index c1dff2c..7fdae9b 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -97,7 +97,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) 0x); return true; } - udelay(15); + usleep_range(15, 20); } return false; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index addf775..25fc268 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -58,7 +58,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) return 0; } - mdelay(2); + usleep_range(2000, 2500); /* ...wait until PHY is ready and read the selected radio revision */ ath5k_hw_reg_write(ah, 0x1c16, AR5K_PHY(0x34)); @@ -308,9 +308,9 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, delay = delay 2; /* XXX: /2 on turbo ? Let's be safe * for now */ - udelay(100 + delay); + usleep_range(100 + delay, 100 + (2 * delay)); } else { - mdelay(1); + usleep_range(1000, 1500); } } @@ -1083,7 +1083,7 @@ static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, data = ath5k_hw_rf5110_chan2athchan(channel); ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); - mdelay(1); + usleep_range(1000, 1500); return 0; } @@ -1454,7 +1454,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1467,7 +1467,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); @@ -1504,7 +1504,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); - mdelay(1); + usleep_range(1000, 1500); /* * Enable calibration and wait until completion @@ -3396,7 +3396,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; - mdelay(1); + usleep_range(1000, 1500); /* * Write RF buffer @@ -3417,10 +3417,10 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, } } else if (ah-ah_version == AR5K_AR5210) { - mdelay(1); + usleep_range(1000, 1500); /* Disable phy and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); } /* Set channel on PHY */ @@ -3446,7 +3446,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, for (i = 0; i = 20; i++) { if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) 0x10)) break; - udelay(200); + usleep_range(200, 250); } ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 2abac25..de28be4 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++
[ath5k-devel] [PATCH 04/13] ath5k: Cleanups v1
No functional changes, just a few comments/documentation/cleanup Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/base.c | 112 - drivers/net/wireless/ath/ath5k/dma.c | 17 - 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c18d310..47194a4 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2149,69 +2149,110 @@ ath5k_intr(int irq, void *dev_id) enum ath5k_int status; unsigned int counter = 1000; + + /* +* If hw is not ready (or detached) and we get an +* interrupt, or if we have no interrupts pending +* (that means it's not for us) skip it. +* +* NOTE: Group 0/1 PCI interface registers are not +* supported on WiSOCs, so we can't check for pending +* interrupts (ISR belongs to another register group +* so we are ok). +*/ if (unlikely(test_bit(ATH_STAT_INVALID, ah-status) || - ((ath5k_get_bus_type(ah) != ATH_AHB) - !ath5k_hw_is_intr_pending(ah + ((ath5k_get_bus_type(ah) != ATH_AHB) + !ath5k_hw_is_intr_pending(ah return IRQ_NONE; + /** Main loop **/ do { - ath5k_hw_get_isr(ah, status); /* NB: clears IRQ too */ + ath5k_hw_get_isr(ah, status); /* NB: clears IRQ too */ + ATH5K_DBG(ah, ATH5K_DEBUG_INTR, status 0x%x/0x%x\n, status, ah-imask); + + /* +* Fatal hw error - Log and reset +* +* Fatal errors are unrecoverable so we have to +* reset the card. These errors include bus and +* dma errors. +*/ if (unlikely(status AR5K_INT_FATAL)) { - /* -* Fatal errors are unrecoverable. -* Typically these are caused by DMA errors. -*/ + ATH5K_DBG(ah, ATH5K_DEBUG_RESET, fatal int, resetting\n); ieee80211_queue_work(ah-hw, ah-reset_work); + + /* +* RX Overrun - Count and reset if needed +* +* Receive buffers are full. Either the bus is busy or +* the CPU is not fast enough to process all received +* frames. +*/ } else if (unlikely(status AR5K_INT_RXORN)) { + /* -* Receive buffers are full. Either the bus is busy or -* the CPU is not fast enough to process all received -* frames. * Older chipsets need a reset to come out of this * condition, but we treat it as RX for newer chips. -* We don't know exactly which versions need a reset - +* We don't know exactly which versions need a reset * this guess is copied from the HAL. */ ah-stats.rxorn_intr++; + if (ah-ah_mac_srev AR5K_SREV_AR5212) { ATH5K_DBG(ah, ATH5K_DEBUG_RESET, rx overrun, resetting\n); ieee80211_queue_work(ah-hw, ah-reset_work); } else ath5k_schedule_rx(ah); + } else { + + /* Software Beacon Alert - Schedule beacon tasklet */ if (status AR5K_INT_SWBA) tasklet_hi_schedule(ah-beacontq); - if (status AR5K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work at - * least on older hardware revs. - */ + /* +* No more RX descriptors - Just count +* +* NB: the hardware should re-read the link when +* RXE bit is written, but it doesn't work at +* least on older hardware revs. +*/ + if (status AR5K_INT_RXEOL) ah-stats.rxeol_intr++; - } - if (status AR5K_INT_TXURN) { - /* bump tx trigger level */ + + + /* TX Underrun -
[ath5k-devel] [PATCH 10/13] ath5k: MRR support and 2GHz radio override belong in ah_capabilities
MRR support and 2GHz radio override belong in ah_capabilities and we should use them (e.g. so far we used to set mrr descriptor without checking if MRR support is enabled + we checked for MRR support 2 times, one by trying to set up an MRR descriptor and another one based on MAC version). Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ahb.c|4 ++- drivers/net/wireless/ath/ath5k/ath5k.h | 12 drivers/net/wireless/ath/ath5k/attach.c |5 --- drivers/net/wireless/ath/ath5k/base.c | 47 --- drivers/net/wireless/ath/ath5k/caps.c | 27 + 5 files changed, 47 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index e5be7e70..ee7ea57 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -166,7 +166,9 @@ static int ath_ahb_probe(struct platform_device *pdev) if (to_platform_device(ah-dev)-id == 0 (bcfg-config-flags (BD_WLAN0 | BD_WLAN1)) == (BD_WLAN1 | BD_WLAN0)) - __set_bit(ATH_STAT_2G_DISABLED, ah-status); + ah-ah_capabilities.cap_needs_2GHz_ovr = true; + else + ah-ah_capabilities.cap_needs_2GHz_ovr = false; } ret = ath5k_init_ah(ah, ath_ahb_bus_ops); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 743938c..304cc92 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1159,6 +1159,8 @@ struct ath5k_capabilities { } cap_queues; bool cap_has_phyerr_counters; + bool cap_has_mrr_support; + bool cap_needs_2GHz_ovr; }; /* size of noise floor history (keep it a power of two) */ @@ -1274,13 +1276,11 @@ struct ath5k_hw { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 6); + DECLARE_BITMAP(status, 4); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ -#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ -#define ATH_STAT_PROMISC 2 -#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ -#define ATH_STAT_STARTED 4 /* opened irqs enabled */ -#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ +#define ATH_STAT_PROMISC 1 +#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */ +#define ATH_STAT_STARTED 3 /* opened irqs enabled */ unsigned intfilter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index b69e057..d7114c7 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -306,11 +306,6 @@ int ath5k_hw_init(struct ath5k_hw *ah) goto err; } - if (test_bit(ATH_STAT_2G_DISABLED, ah-status)) { - __clear_bit(AR5K_MODE_11B, ah-ah_capabilities.cap_mode); - __clear_bit(AR5K_MODE_11G, ah-ah_capabilities.cap_mode); - } - /* Crypto settings */ common-keymax = (ah-ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index b901721..ef0ffcd 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -725,21 +725,24 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, if (ret) goto err_unmap; - memset(mrr_rate, 0, sizeof(mrr_rate)); - memset(mrr_tries, 0, sizeof(mrr_tries)); - for (i = 0; i 3; i++) { - rate = ieee80211_get_alt_retry_rate(ah-hw, info, i); - if (!rate) - break; + /* Set up MRR descriptor */ + if (ah-ah_capabilities.cap_has_mrr_support) { + memset(mrr_rate, 0, sizeof(mrr_rate)); + memset(mrr_tries, 0, sizeof(mrr_tries)); + for (i = 0; i 3; i++) { + rate = ieee80211_get_alt_retry_rate(ah-hw, info, i); + if (!rate) + break; - mrr_rate[i] = rate-hw_value; - mrr_tries[i] = info-control.rates[i + 1].count; - } + mrr_rate[i] = rate-hw_value; + mrr_tries[i] = info-control.rates[i + 1].count; + } - ath5k_hw_setup_mrr_tx_desc(ah, ds, - mrr_rate[0], mrr_tries[0], -
[ath5k-devel] [PATCH 11/13] ath5k: ath5k_ani_period_restart only touches struct ath5k_ani_state
No need to take ath5k_hw as an argument. Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ani.c |7 +++ 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 2dfcf1a..bf67416 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -440,13 +440,12 @@ ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, /** * ath5k_ani_period_restart() - Restart ANI period - * @ah: The struct ath5k_hw * @as: The struct ath5k_ani_state * * Just reset counters, so they are clear for the next ani period. */ static void -ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) +ath5k_ani_period_restart(struct ath5k_ani_state *as) { /* keep last values for debugging */ as-last_ofdm_errors = as-ofdm_errors; @@ -502,7 +501,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah) /* too many PHY errors - we have to raise immunity */ bool ofdm_flag = as-ofdm_errors ofdm_high ? true : false; ath5k_ani_raise_immunity(ah, as, ofdm_flag); - ath5k_ani_period_restart(ah, as); + ath5k_ani_period_restart(as); } else if (as-listen_time 5 * ATH5K_ANI_LISTEN_PERIOD) { /* If more than 5 (TODO: why 5?) periods have passed and we got @@ -514,7 +513,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah) if (as-ofdm_errors = ofdm_low as-cck_errors = cck_low) ath5k_ani_lower_immunity(ah, as); - ath5k_ani_period_restart(ah, as); + ath5k_ani_period_restart(as); } } -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 03/13] ath5k: Add TXNOFRM to INT_TX_ALL
Add TXNOFRM to INT_TX_ALL since it's a TX interrupt too. Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/ath5k.h |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 0f42a57..b8abdbc 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -856,6 +856,7 @@ enum ath5k_int { AR5K_INT_TX_ALL = AR5K_INT_TXOK | AR5K_INT_TXDESC | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM | AR5K_INT_TXEOL | AR5K_INT_TXURN, -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 00/13] ath5k: A few updates + cleanups + kerneldoc
This series of patches includes some stability fixes related to interrupt handling, an updated version of a calibration-related patch I posted some time ago but never submited here and a new module parameter to disable GPIO based rfkill switch (we had a few bug reports on that recently). It also adds kernel doc on all ath5k_hw_* functions and structs (needs some more work but it should be fine, I reviewed the output, spell-ckecked it etc) and a few minor fixes and optimizations. Nick Kossifidis (13): ath5k: Switch from read-and-clear to write-to-clear method when handling PISR/SISR registers. ath5k: Maintain PISR snapshot ath5k: Add TXNOFRM to INT_TX_ALL ath5k: Cleanups v1 ath5k: Calibration re-work ath5k: Use usleep_range where possible ath5k: Cleanups v2 + add kerneldoc on all hw functions ath5k: We always do full calibration on AR5210 ath5k: Add a module parameter to disable hw rf kill switch ath5k: MRR support and 2GHz radio override belong in ah_capabilities ath5k: ath5k_ani_period_restart only touches struct ath5k_ani_state ath5k: Renumber hw queue ids ath5k: Optimize ath5k_cw_validate drivers/net/wireless/ath/ath5k/ahb.c |4 +- drivers/net/wireless/ath/ath5k/ani.c | 91 ++-- drivers/net/wireless/ath/ath5k/ani.h | 32 +- drivers/net/wireless/ath/ath5k/ath5k.h| 566 +-- drivers/net/wireless/ath/ath5k/attach.c | 16 +- drivers/net/wireless/ath/ath5k/base.c | 277 +++--- drivers/net/wireless/ath/ath5k/caps.c | 27 +- drivers/net/wireless/ath/ath5k/desc.c | 217 ++-- drivers/net/wireless/ath/ath5k/desc.h | 124 +++-- drivers/net/wireless/ath/ath5k/dma.c | 380 - drivers/net/wireless/ath/ath5k/gpio.c | 81 +++- drivers/net/wireless/ath/ath5k/initvals.c | 75 ++- drivers/net/wireless/ath/ath5k/pci.c |2 +- drivers/net/wireless/ath/ath5k/pcu.c | 222 +--- drivers/net/wireless/ath/ath5k/phy.c | 852 +++-- drivers/net/wireless/ath/ath5k/qcu.c | 136 -- drivers/net/wireless/ath/ath5k/reg.h | 21 +- drivers/net/wireless/ath/ath5k/reset.c| 230 ++-- drivers/net/wireless/ath/ath5k/rfbuffer.h | 59 ++- drivers/net/wireless/ath/ath5k/rfgain.h | 22 +- 20 files changed, 2457 insertions(+), 977 deletions(-) -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] [PATCH 08/13] ath5k: We always do full calibration on AR5210
There is no short calibration on AR5210, make sure we treat it always as full calibration. Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/phy.c |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 3bb42a4..1a166d7 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1674,6 +1674,9 @@ ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, u32 phy_sig, phy_agc, phy_sat, beacon; int ret; + if (!(ah-ah_cal_mask AR5K_CALIBRATION_FULL)) + return 0; + /* * Disable beacons and RX/TX queues, wait */ -- 1.7.8.rc1 ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 06/13] ath5k: Use usleep_range where possible
On 2011-11-20 8:56 AM, Nick Kossifidis wrote: Use usleep_range where possible to reduce busy waits Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/attach.c |2 +- drivers/net/wireless/ath/ath5k/pci.c|2 +- drivers/net/wireless/ath/ath5k/phy.c| 22 +++--- drivers/net/wireless/ath/ath5k/reset.c | 14 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) @@ -1454,7 +1454,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1467,7 +1467,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); Are you sure this is safe? This looks like it's being called from tasklet context, and I think usleep_range is not allowed there. - Felix ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 06/13] ath5k: Use usleep_range where possible
2011/11/20 Felix Fietkau n...@openwrt.org: On 2011-11-20 8:56 AM, Nick Kossifidis wrote: Use usleep_range where possible to reduce busy waits Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/pci.c | 2 +- drivers/net/wireless/ath/ath5k/phy.c | 22 +++--- drivers/net/wireless/ath/ath5k/reset.c | 14 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) @@ -1454,7 +1454,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1467,7 +1467,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); Are you sure this is safe? This looks like it's being called from tasklet context, and I think usleep_range is not allowed there. - Felix Reset runs in process context. Calls to reset are done directly from non-interrupt context (e.g. during init) or through a work queue, not a tasklet. They are also locked using a mutex lock, not a spinlock so we should be fine. I did a few tests to be on the safe side and run this on a multi-core system with an AR2425 with no problems/deadlocks or anything. -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 13/13] ath5k: Optimize ath5k_cw_validate
On Sun, Nov 20, 2011 at 09:56:28AM +0200, Nick Kossifidis wrote: + /* Check if cw_req + 1 a power of 2 */ + if (!((cw_req + 1) cw_req)) + return cw_req; + + /* Check if cw_req is a power of 2 */ + if (!(cw_req (cw_req - 1))) + return cw_req - 1; There's is_power_of_two() in log2.h .. but this whole thing could also be something like roundup_pow_of_two(cw) maybe? -- Bob Copeland %% www.bobcopeland.com ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 06/13] ath5k: Use usleep_range where possible
On 11/20/2011 04:43 PM, Nick Kossifidis wrote: 2011/11/20 Felix Fietkau n...@openwrt.org: On 2011-11-20 8:56 AM, Nick Kossifidis wrote: Use usleep_range where possible to reduce busy waits Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/attach.c |2 +- drivers/net/wireless/ath/ath5k/pci.c|2 +- drivers/net/wireless/ath/ath5k/phy.c| 22 +++--- drivers/net/wireless/ath/ath5k/reset.c | 14 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) @@ -1454,7 +1454,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1467,7 +1467,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); Are you sure this is safe? This looks like it's being called from tasklet context, and I think usleep_range is not allowed there. - Felix Reset runs in process context. Calls to reset are done directly from non-interrupt context (e.g. during init) or through a work queue, not a tasklet. They are also locked using a mutex lock, not a spinlock so we should be fine. But those two are not reset, but calibrate. And calibration is performed in a tasklet. thanks, -- js ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 13/13] ath5k: Optimize ath5k_cw_validate
2011/11/20 Bob Copeland m...@bobcopeland.com: On Sun, Nov 20, 2011 at 09:56:28AM +0200, Nick Kossifidis wrote: + /* Check if cw_req + 1 a power of 2 */ + if (!((cw_req + 1) cw_req)) + return cw_req; + + /* Check if cw_req is a power of 2 */ + if (!(cw_req (cw_req - 1))) + return cw_req - 1; There's is_power_of_two() in log2.h .. but this whole thing could also be something like roundup_pow_of_two(cw) maybe? Nice catch ! I didn't knew about log2.h, seems interesting :-) roundup_pow_of_two(n) - 1 should take away that while loop but in most cases we 'll get a correct cw value so is_power_of_two(cw_req + 1) would take care of that faster. I'll post an update -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 06/13] ath5k: Use usleep_range where possible
2011/11/20 Jiri Slaby jirisl...@gmail.com: On 11/20/2011 04:43 PM, Nick Kossifidis wrote: 2011/11/20 Felix Fietkau n...@openwrt.org: On 2011-11-20 8:56 AM, Nick Kossifidis wrote: Use usleep_range where possible to reduce busy waits Signed-off-by: Nick Kossifidis mickfl...@gmail.com --- drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/pci.c | 2 +- drivers/net/wireless/ath/ath5k/phy.c | 22 +++--- drivers/net/wireless/ath/ath5k/reset.c | 14 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) @@ -1454,7 +1454,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); - mdelay(2); + usleep_range(2000, 2500); /* * Set the channel (with AGC turned off) @@ -1467,7 +1467,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Activate PHY and wait */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); - mdelay(1); + usleep_range(1000, 1500); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); Are you sure this is safe? This looks like it's being called from tasklet context, and I think usleep_range is not allowed there. - Felix Reset runs in process context. Calls to reset are done directly from non-interrupt context (e.g. during init) or through a work queue, not a tasklet. They are also locked using a mutex lock, not a spinlock so we should be fine. But those two are not reset, but calibrate. And calibration is performed in a tasklet. thanks, -- js Just noticed I missed that part on 05, there is no need to run calibration through a tasklet, will post an update on 05... -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] [PATCH 02/13] ath5k: Maintain PISR snapshot
2011/11/21 Adrian Chadd adr...@freebsd.org: .. replying to this after having not slept for 24 hours, thanks to being in transit between the US and Western Australia.. Ouch ! I've done that a lot lately, without traveling :P On 20 November 2011 15:56, Nick Kossifidis mickfl...@gmail.com wrote: Since we dont read a snapshot of the interrupt registers it might be possible to get a new interrupt while reading them. In this case we should make sure that we clear all SISR bits we get from PISR. Just to be clear, you _shouldn't_ clear the secondary status mask bit in the primary status register when you write back 1's to the primary ISR. Clear the bits that you read in the secondary status registers. If you clear the relevant bit in the primary status register then you may also skip perfectly valid interrupts. You don't need to check the secondary registers and the primary ISR bits for consistency. Just read what I did in freebsd-head : src/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c . it works fine. Adrian ACK, thanks for the update ! It's just that docs say nothing about when and how PISR gets updated so i tried to manually update it. -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
[ath5k-devel] A weird hw crypto bug...
Some time ago we had a few reports of AR2413 cards being unable to encrypt packets of specific lengths. From https://bugs.launchpad.net/ubuntu/+source/linux/+bug/568090, user Musaraigne did some further investigation/debuging on this: The cause of the high and unpredictable latencies is that packets are dropped depending on their size. According to my tests, packet sizes of the form size = 128*k + 81 + m or size = 128*k + 105 + m for any k=2 and 0=m=7 are dropped randomly in 90-95% of the cases. Conversely, all other packet sizes work fine. You can see for yourself if this is true on your system: ping -M do -s 596 www.google.com should result in 90% packet loss (because 624 = 128*4 + 105 + 7; the 28 byte difference comes from network headers added by ping) while ping -M do -s 597 www.google.com should result in negligible packet loss. So far I couldn't reproduce this bug with my AR2413 and now after e few user reports I'm almost sure that it's only present on cards created by Askey. I verified it again recently based on a bug report from an OpenSUSE user here... https://bugzilla.novell.com/show_bug.cgi?id=731576 What seems weird is that some users reported that MadWiFi worked fine on these cards (I have no idea what happens on their windows driver, maybe they disable hw crypto) ! Since for hw crypto we use code from the common ath module (and I think this is the same with HAL) I don't see how that can happen. Anyway my question is how to handle this: a) Just disable hw crypto for all AR2413 cards made by Askey b) If we handle such card do some padding based on Musaraigne's findings I'd like to go with b but I don't know how to do it correctly without corrupting anything. Any ideas ? -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] A weird hw crypto bug...
On 21 November 2011 12:08, Nick Kossifidis mickfl...@gmail.com wrote: Some time ago we had a few reports of AR2413 cards being unable to encrypt packets of specific lengths. From https://bugs.launchpad.net/ubuntu/+source/linux/+bug/568090, user Musaraigne did some further investigation/debuging on this: The cause of the high and unpredictable latencies is that packets are dropped depending on their size. According to my tests, packet sizes of the form size = 128*k + 81 + m or size = 128*k + 105 + m for any k=2 and 0=m=7 are dropped randomly in 90-95% of the cases. Conversely, all other packet sizes work fine. That seems a bit odd. Erm, how do they fail? * Does the hardware just plain fail at encrypting the frame? * Does the hardware just plain fail to _TX_ the frame of that size? (ie, if you disable crypto and take padding into account, does it fail?) * What about other encryption types? AES? TKIP? WEP? None? :-) * This is a PCIe NIC, right? Are there some kind of weird bus bugs that you're seeing with this particular NIC and this particular bus glue? Since Madwifi works, I wonder if FreeBSD also works. If so, there's only a few places I'd bet you'll find weird stuff: * how the bus is setup during attach (eg overriding PCI values); * which crypto key slots are allocated; * are you still doing split keys on that hardware? or are they combined like the ar5416+ chips are? * are you perhaps doing multi-descriptor TX frames and you've not set the encryption bits correctly? IIRC, the enctype field needs to match on all descriptors of a frame (eg, if your packet is a chain rather than a single skb, you need to make sure you're copying the descriptor fields right.) * what about the frame and header length fields? and encryption padding? are they all setup the same with madwifi versus ath5k? I bet a bit of methodical poking is going to reveal this bug. I find it rather annoying that ath5k/ath9k have lots of encryption issues but I've not had any reports of encryption on FreeBSD failing (save where the AP is totally lying about which keyidx a frame is encrypted with.) It's possible that you're seeing these errors because more people are using ath5k then FreeBSD, but still: * does freebsd-9 (wifi) work on the same hardware? Nick, can you find out if someone can send us one of these weird NICs? I'll throw it into my pile-o-old-stuff-to-test and do some regression testing with it. Adrian ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel
Re: [ath5k-devel] A weird hw crypto bug...
2011/11/21 Adrian Chadd adr...@freebsd.org: On 21 November 2011 12:08, Nick Kossifidis mickfl...@gmail.com wrote: Some time ago we had a few reports of AR2413 cards being unable to encrypt packets of specific lengths. From https://bugs.launchpad.net/ubuntu/+source/linux/+bug/568090, user Musaraigne did some further investigation/debuging on this: The cause of the high and unpredictable latencies is that packets are dropped depending on their size. According to my tests, packet sizes of the form size = 128*k + 81 + m or size = 128*k + 105 + m for any k=2 and 0=m=7 are dropped randomly in 90-95% of the cases. Conversely, all other packet sizes work fine. That seems a bit odd. Erm, how do they fail? * Does the hardware just plain fail at encrypting the frame? * Does the hardware just plain fail to _TX_ the frame of that size? (ie, if you disable crypto and take padding into account, does it fail?) * What about other encryption types? AES? TKIP? WEP? None? :-) * This is a PCIe NIC, right? Are there some kind of weird bus bugs that you're seeing with this particular NIC and this particular bus glue? This is about specific AR2413 cards made by Askey, AR2413 cards in general work fine, I have one myself. Problem is when hw encryption is enabled (not sure about WEP, I think I've seen a report on WEP also) when packets of specific lengths are dropped. They work O.K. without encryption or with sw encryption. I haven't seen any report with dumps etc so I don't know if packers are corrupted or never transmitted etc, it's just weird that it happens only on specific AR2413 cards, not any AR2413 card (that means in general we handle hw encryption correctly as it works fine on most cards, in fact right now I think that's the only active bug we have on encryption). The way I see it it's a hw issue found on these implementations that we don't handle. Btw AR2413 is plain pci card, only AR5424/2424/2425 are pci-e from ar5k series (it's also AR5418 but it's handled by ath9k). Since Madwifi works, I wonder if FreeBSD also works. If so, there's only a few places I'd bet you'll find weird stuff: * how the bus is setup during attach (eg overriding PCI values); * which crypto key slots are allocated; * are you still doing split keys on that hardware? or are they combined like the ar5416+ chips are? When we had crypto code inside ath5k we did what the old HAL did (via rev. engineering), now we use the common code from the ath module, so we do whatever ath9k does (and I think MadWiFi too). Again hw crypto works fine, even on AR2413 cards, it's this vendor that has done something weird that results tx failures on hw encryption. Plus I don't know what version of MadWiFi they used or if they used hw crypto on MadWiFi at all. * are you perhaps doing multi-descriptor TX frames and you've not set the encryption bits correctly? IIRC, the enctype field needs to match on all descriptors of a frame (eg, if your packet is a chain rather than a single skb, you need to make sure you're copying the descriptor fields right.) No fast frames here or multi-descriptor stuff. * what about the frame and header length fields? and encryption padding? are they all setup the same with madwifi versus ath5k? That would show up as most of the things you mention above on any card since it's common code, or even on a specific chip version/revision. Here we have this issue with a specific implementation and everything works fine on other implementations with the same chip. I bet a bit of methodical poking is going to reveal this bug. I find it rather annoying that ath5k/ath9k have lots of encryption issues but I've not had any reports of encryption on FreeBSD failing (save where the AP is totally lying about which keyidx a frame is encrypted with.) It's possible that you're seeing these errors because more people are using ath5k then FreeBSD, but still: * does freebsd-9 (wifi) work on the same hardware? No idea :-( Nick, can you find out if someone can send us one of these weird NICs? I'll throw it into my pile-o-old-stuff-to-test and do some regression testing with it. Haven't found so far but I think it's clearly a hw issue (I've done some testing on my AR2413 and it seems fine) and since we know what packet lengths fail maybe we can create a workaround with padding etc. -- GPG ID: 0xEE878588 As you read this post global entropy rises. Have Fun ;-) Nick ___ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel