/* * Set tx retry limits on DCU */ void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, unsigned int queue) { /* Single data queue on AR5210 */ if (ah->ah_version == AR5K_AR5210) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; if (queue > 0) return; ath5k_hw_reg_write(ah, (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) | AR5K_REG_SM(ah->ah_retry_long, AR5K_NODCU_RETRY_LMT_SLG_RETRY) | AR5K_REG_SM(ah->ah_retry_short, AR5K_NODCU_RETRY_LMT_SSH_RETRY) | AR5K_REG_SM(ah->ah_retry_long, AR5K_NODCU_RETRY_LMT_LG_RETRY) | AR5K_REG_SM(ah->ah_retry_short, AR5K_NODCU_RETRY_LMT_SH_RETRY), AR5K_NODCU_RETRY_LMT); /* DCU on AR5211+ */ } else { ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_retry_long, AR5K_DCU_RETRY_LMT_RTS) | AR5K_REG_SM(ah->ah_retry_long, AR5K_DCU_RETRY_LMT_STA_RTS) | AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short), AR5K_DCU_RETRY_LMT_STA_DATA), AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); } }
/** * ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU * * @ah The &struct ath5k_hw * @slot_time Slot time in us * * Sets the global IFS intervals on DCU (also works on AR5210) for * the given slot time and the current bwmode. */ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) { struct ieee80211_channel *channel = ah->ah_current_channel; struct ieee80211_rate *rate; u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock; u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) return -EINVAL; sifs = ath5k_hw_get_default_sifs(ah); sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); /* EIFS * Txtime of ack at lowest rate + SIFS + DIFS * (DIFS = SIFS + 2 * Slot time) * * Note: HAL has some predefined values for EIFS * Turbo: (37 + 2 * 6) * Default: (74 + 2 * 9) * Half: (149 + 2 * 13) * Quarter: (298 + 2 * 21) * * (74 + 2 * 6) for AR5210 default and turbo ! * * According to the formula we have * ack_tx_time = 25 for turbo and * ack_tx_time = 42.5 * clock multiplier * for default/half/quarter. * * This can't be right, 42 is what we would get * from ath5k_hw_get_frame_dur_for_bwmode or * ieee80211_generic_frame_duration for zero frame * length and without SIFS ! * * Also we have different lowest rate for 802.11a */ if (channel->band == IEEE80211_BAND_5GHZ) rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; else rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); /* ack_tx_time includes an SIFS already */ eifs = ack_tx_time + sifs + 2 * slot_time; eifs_clock = ath5k_hw_htoclock(ah, eifs); /* Set IFS settings on AR5210 */ if (ah->ah_version == AR5K_AR5210) { u32 pifs, pifs_clock, difs, difs_clock; /* Set slot time */ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); /* Set EIFS */ eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS); /* PIFS = Slot time + SIFS */ pifs = slot_time + sifs; pifs_clock = ath5k_hw_htoclock(ah, pifs); pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS); /* DIFS = SIFS + 2 * Slot time */ difs = sifs + 2 * slot_time; difs_clock = ath5k_hw_htoclock(ah, difs); /* Set SIFS/DIFS */ ath5k_hw_reg_write(ah, (difs_clock << AR5K_IFS0_DIFS_S) | sifs_clock, AR5K_IFS0); /* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */ ath5k_hw_reg_write(ah, pifs_clock | eifs_clock | (AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S), AR5K_IFS1); return 0; } /* Set IFS slot time */ ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); /* Set EIFS interval */ ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS); /* Set SIFS interval in usecs */ AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC, AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC, sifs); /* Set SIFS interval in clock cycles */ ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS); return 0; }
/** * ath5k_hw_reset_tx_queue - Initialize a single hw queue * * @ah The &struct ath5k_hw * @queue The hw queue number * * Set DFS properties for the given transmit queue on DCU * and configures all queue-specific parameters. */ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); tq = &ah->ah_txq[queue]; /* Skip if queue inactive or if we are on AR5210 * that doesn't have QCU/DCU */ if ((ah->ah_version == AR5K_AR5210) || (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)) return 0; /* * Set contention window (cw_min/cw_max) * and arbitrated interframe space (aifs)... */ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS), AR5K_QUEUE_DFS_LOCAL_IFS(queue)); /* * Set tx retry limits for this queue */ ath5k_hw_set_tx_retry_limits(ah, queue); /* * Set misc registers */ /* Enable DCU to wait for next fragment from QCU */ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), AR5K_DCU_MISC_FRAG_WAIT); /* On Maui and Spirit use the global seqnum on DCU */ if (ah->ah_mac_version < AR5K_SREV_AR5211) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), AR5K_DCU_MISC_SEQNUM_CTL); /* Constant bit rate period */ if (tq->tqi_cbr_period) { ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, AR5K_QCU_CBRCFG_INTVAL) | AR5K_REG_SM(tq->tqi_cbr_overflow_limit, AR5K_QCU_CBRCFG_ORN_THRES), AR5K_QUEUE_CBRCFG(queue)); AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_CBR); if (tq->tqi_cbr_overflow_limit) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_CBR_THRES_ENABLE); } /* Ready time interval */ if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB)) ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, AR5K_QCU_RDYTIMECFG_INTVAL) | AR5K_QCU_RDYTIMECFG_ENABLE, AR5K_QUEUE_RDYTIMECFG(queue)); if (tq->tqi_burst_time) { ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, AR5K_DCU_CHAN_TIME_DUR) | AR5K_DCU_CHAN_TIME_ENABLE, AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_RDY_VEOL_POLICY); } /* Enable/disable Post frame backoff */ if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, AR5K_QUEUE_DFS_MISC(queue)); /* Enable/disable fragmentation burst backoff */ if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, AR5K_QUEUE_DFS_MISC(queue)); /* * Set registers by queue type */ switch (tq->tqi_type) { case AR5K_TX_QUEUE_BEACON: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_DBA_GT | AR5K_QCU_MISC_CBREXP_BCN_DIS | AR5K_QCU_MISC_BCN_ENABLE); AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << AR5K_DCU_MISC_ARBLOCK_CTL_S) | AR5K_DCU_MISC_ARBLOCK_IGNORE | AR5K_DCU_MISC_POST_FR_BKOFF_DIS | AR5K_DCU_MISC_BCN_ENABLE); break; case AR5K_TX_QUEUE_CAB: /* XXX: use BCN_SENT_GT, if we can figure out how */ AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_FRSHED_DBA_GT | AR5K_QCU_MISC_CBREXP_DIS | AR5K_QCU_MISC_CBREXP_BCN_DIS); ath5k_hw_reg_write(ah, ((tq->tqi_ready_time - (AR5K_TUNE_SW_BEACON_RESP - AR5K_TUNE_DMA_BEACON_RESP) - AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | AR5K_QCU_RDYTIMECFG_ENABLE, AR5K_QUEUE_RDYTIMECFG(queue)); AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << AR5K_DCU_MISC_ARBLOCK_CTL_S)); break; case AR5K_TX_QUEUE_UAPSD: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), AR5K_QCU_MISC_CBREXP_DIS); break; case AR5K_TX_QUEUE_DATA: default: break; } /* TODO: Handle frame compression */ /* * Enable interrupts for this tx queue * in the secondary interrupt mask registers */ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); /* Update secondary interrupt mask registers */ /* Filter out inactive queues */ ah->ah_txq_imr_txok &= ah->ah_txq_status; ah->ah_txq_imr_txerr &= ah->ah_txq_status; ah->ah_txq_imr_txurn &= ah->ah_txq_status; ah->ah_txq_imr_txdesc &= ah->ah_txq_status; ah->ah_txq_imr_txeol &= ah->ah_txq_status; ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; ah->ah_txq_imr_qtrig &= ah->ah_txq_status; ah->ah_txq_imr_nofrm &= ah->ah_txq_status; ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, AR5K_SIMR0_QCU_TXOK) | AR5K_REG_SM(ah->ah_txq_imr_txdesc, AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, AR5K_SIMR1_QCU_TXERR) | AR5K_REG_SM(ah->ah_txq_imr_txeol, AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); /* Update SIMR2 but don't overwrite rest simr2 settings */ AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_REG_SM(ah->ah_txq_imr_txurn, AR5K_SIMR2_QCU_TXURN)); ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, AR5K_SIMR3_QCBRORN) | AR5K_REG_SM(ah->ah_txq_imr_cbrurn, AR5K_SIMR3_QCBRURN), AR5K_SIMR3); ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, AR5K_SIMR4_QTRIG), AR5K_SIMR4); /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); /* No queue has TXNOFRM enabled, disable the interrupt * by setting AR5K_TXNOFRM to zero */ if (ah->ah_txq_imr_nofrm == 0) ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); /* Set QCU mask for this DCU to save power */ AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue); return 0; }
/** * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor * @ah: The &struct ath5k_hw * @desc: The &struct ath5k_desc * @pkt_len: Frame length in bytes * @hdr_len: Header length in bytes (only used on AR5210) * @padsize: Any padding we've added to the frame length * @type: One of enum ath5k_pkt_type * @tx_power: Tx power in 0.5dB steps * @tx_rate0: HW idx for transmission rate * @tx_tries0: Max number of retransmissions * @key_index: Index on key table to use for encryption * @antenna_mode: Which antenna to use (0 for auto) * @flags: One of AR5K_TXDESC_* flags (desc.h) * @rtscts_rate: HW idx for RTS/CTS transmission rate * @rtscts_duration: What to put on duration field on the header of RTS/CTS * * Internal function to initialize a 2-Word TX control descriptor * found on AR5210 and AR5211 MACs chips. * * Returns 0 on success or -EINVAL on false input */ static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, int padsize, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { u32 frame_type; struct ath5k_hw_2w_tx_ctl *tx_ctl; unsigned int frame_len; tx_ctl = &desc->ud.ds_tx5210.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { ATH5K_ERR(ah, "zero retries\n"); WARN_ON(1); return -EINVAL; } if (unlikely(tx_rate0 == 0)) { ATH5K_ERR(ah, "zero rate\n"); WARN_ON(1); return -EINVAL; } /* Clear descriptor */ memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); /* Setup control descriptor */ /* Verify and set frame length */ /* remove padding we might have added before */ frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ /* NB: beacon's BufLen must be a multiple of 4 bytes */ if (type == AR5K_PKT_TYPE_BEACON) pkt_len = roundup(pkt_len, 4); if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* * Verify and set header length (only 5210) */ if (ah->ah_version == AR5K_AR5210) { if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210) return -EINVAL; tx_ctl->tx_control_0 |= AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210); } /*Differences between 5210-5211*/ if (ah->ah_version == AR5K_AR5210) { switch (type) { case AR5K_PKT_TYPE_BEACON: case AR5K_PKT_TYPE_PROBE_RESP: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; break; case AR5K_PKT_TYPE_PIFS: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; break; default: frame_type = type; break; } tx_ctl->tx_control_0 |= AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); } else { tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211); } #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ } #define _TX_FLAGS_5211(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); if (ah->ah_version == AR5K_AR5211) { _TX_FLAGS_5211(0, VEOL); _TX_FLAGS_5211(1, NOACK); } #undef _TX_FLAGS #undef _TX_FLAGS_5211 /* * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { tx_ctl->tx_control_0 |= AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX); } /* * RTS/CTS Duration [5210 ?] */ if ((ah->ah_version == AR5K_AR5210) && (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) tx_ctl->tx_control_1 |= rtscts_duration & AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210; return 0; }
/** * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor * @ah: The &struct ath5k_hw * @desc: The &struct ath5k_desc * @pkt_len: Frame length in bytes * @hdr_len: Header length in bytes (only used on AR5210) * @padsize: Any padding we've added to the frame length * @type: One of enum ath5k_pkt_type * @tx_power: Tx power in 0.5dB steps * @tx_rate0: HW idx for transmission rate * @tx_tries0: Max number of retransmissions * @key_index: Index on key table to use for encryption * @antenna_mode: Which antenna to use (0 for auto) * @flags: One of AR5K_TXDESC_* flags (desc.h) * @rtscts_rate: HW idx for RTS/CTS transmission rate * @rtscts_duration: What to put on duration field on the header of RTS/CTS * * Internal function to initialize a 4-Word TX control descriptor * found on AR5212 and later MACs chips. * * Returns 0 on success or -EINVAL on false input */ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, int padsize, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; /* * Use local variables for these to reduce load/store access on * uncached memory */ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { ATH5K_ERR(ah, "zero retries\n"); WARN_ON(1); return -EINVAL; } if (unlikely(tx_rate0 == 0)) { ATH5K_ERR(ah, "zero rate\n"); WARN_ON(1); return -EINVAL; } tx_power += ah->ah_txpower.txp_offset; if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; /* Clear descriptor status area */ memset(&desc->ud.ds_tx5212.tx_stat, 0, sizeof(desc->ud.ds_tx5212.tx_stat)); /* Setup control descriptor */ /* Verify and set frame length */ /* remove padding we might have added before */ frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ /* NB: beacon's BufLen must be a multiple of 4 bytes */ if (type == AR5K_PKT_TYPE_BEACON) pkt_len = roundup(pkt_len, 4); if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); _TX_FLAGS(0, CTSENA); _TX_FLAGS(1, NOACK); #undef _TX_FLAGS /* * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; txctl1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } /* * RTS/CTS */ if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; txctl3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } tx_ctl->tx_control_0 = txctl0; tx_ctl->tx_control_1 = txctl1; tx_ctl->tx_control_2 = txctl2; tx_ctl->tx_control_3 = txctl3; return 0; }
/* * Set beacon timers */ int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state) { u32 cfp_period, next_cfp, dtim, interval, next_beacon; /* * TODO: should be changed through *state * review struct ath5k_beacon_state struct * * XXX: These are used for cfp period bellow, are they * ok ? Is it O.K. for tsf here to be 0 or should we use * get_tsf ? */ u32 dtim_count = 0; /* XXX */ u32 cfp_count = 0; /* XXX */ u32 tsf = 0; /* XXX */ ATH5K_TRACE(ah->ah_sc); /* Return on an invalid beacon state */ if (state->bs_interval < 1) return -EINVAL; interval = state->bs_interval; dtim = state->bs_dtim_period; /* * PCF support? */ if (state->bs_cfp_period > 0) { /* * Enable PCF mode and set the CFP * (Contention Free Period) and timer registers */ cfp_period = state->bs_cfp_period * state->bs_dtim_period * state->bs_interval; next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * state->bs_interval; AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, AR5K_CFP_DUR); ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : next_cfp)) << 3, AR5K_TIMER2); } else { /* Disable PCF mode */ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); } /* * Enable the beacon timer register */ ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); /* * Start the beacon timers */ ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, AR5K_BEACON_PERIOD), AR5K_BEACON); /* * Write new beacon miss threshold, if it appears to be valid * XXX: Figure out right values for min <= bs_bmiss_threshold <= max * and return if its not in range. We can test this by reading value and * setting value to a largest value and seeing which values register. */ AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, state->bs_bmiss_threshold); /* * Set sleep control register * XXX: Didn't find this in 5210 code but since this register * exists also in ar5k's 5210 headers i leave it as common code. */ AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, (state->bs_sleep_duration - 3) << 3); /* * Set enhanced sleep registers on 5212 */ if (ah->ah_version == AR5K_AR5212) { if (state->bs_sleep_duration > state->bs_interval && roundup(state->bs_sleep_duration, interval) == state->bs_sleep_duration) interval = state->bs_sleep_duration; if (state->bs_sleep_duration > dtim && (dtim == 0 || roundup(state->bs_sleep_duration, dtim) == state->bs_sleep_duration)) dtim = state->bs_sleep_duration; if (interval > dtim) return -EINVAL; next_beacon = interval == dtim ? state->bs_next_dtim : state->bs_next_beacon; ath5k_hw_reg_write(ah, AR5K_REG_SM((state->bs_next_dtim - 3) << 3, AR5K_SLEEP0_NEXT_DTIM) | AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | AR5K_SLEEP0_ENH_SLEEP_EN | AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, AR5K_SLEEP1_NEXT_TIM) | AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); ath5k_hw_reg_write(ah, AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); } return 0; }
/* * Initialize the 2-word tx control descriptor on 5210/5211 */ static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, unsigned int tx_power __unused, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index __unused, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate __unused, unsigned int rtscts_duration) { u32 frame_type; struct ath5k_hw_2w_tx_ctl *tx_ctl; unsigned int frame_len; tx_ctl = &desc->ud.ds_tx5210.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continously sends * noise on the channel, so it is important to avoid this. */ if (tx_tries0 == 0) { DBG("ath5k: zero retries\n"); return -EINVAL; } if (tx_rate0 == 0) { DBG("ath5k: zero rate\n"); return -EINVAL; } /* Clear descriptor */ memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); /* Setup control descriptor */ /* Verify and set frame length */ frame_len = pkt_len + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* * Verify and set header length * XXX: I only found that on 5210 code, does it work on 5211 ? */ if (ah->ah_version == AR5K_AR5210) { if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) return -EINVAL; tx_ctl->tx_control_0 |= AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); } /*Diferences between 5210-5211*/ if (ah->ah_version == AR5K_AR5210) { switch (type) { case AR5K_PKT_TYPE_BEACON: case AR5K_PKT_TYPE_PROBE_RESP: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; case AR5K_PKT_TYPE_PIFS: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; default: frame_type = type /*<< 2 ?*/; } tx_ctl->tx_control_0 |= AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); } else { tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); } #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); _TX_FLAGS(1, NOACK); #undef _TX_FLAGS /* * RTS/CTS Duration [5210 ?] */ if ((ah->ah_version == AR5K_AR5210) && (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) tx_ctl->tx_control_1 |= rtscts_duration & AR5K_2W_TX_DESC_CTL1_RTS_DURATION; return 0; }
/* * Initialize the 4-word tx control descriptor on 5212 */ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len __unused, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index __unused, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continously sends * noise on the channel, so it is important to avoid this. */ if (tx_tries0 == 0) { DBG("ath5k: zero retries\n"); return -EINVAL; } if (tx_rate0 == 0) { DBG("ath5k: zero rate\n"); return -EINVAL; } tx_power += ah->ah_txpower.txp_offset; if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; /* Clear descriptor */ memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); /* Setup control descriptor */ /* Verify and set frame length */ frame_len = pkt_len + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); _TX_FLAGS(0, CTSENA); _TX_FLAGS(1, NOACK); #undef _TX_FLAGS /* * RTS/CTS */ if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; tx_ctl->tx_control_2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } return 0; }