📄 ar5210.c
字号:
*/ AR5K_REG_DISABLE_BITS(AR5K_AR5210_DIAG_SW, AR5K_AR5210_DIAG_SW_DIS_TX | AR5K_AR5210_DIAG_SW_DIS_RX); AR5K_REG_WRITE(AR5K_AR5210_BEACON, beacon);#undef AGC_ENABLE#undef AGC_DISABLE return (AH_TRUE);}HAL_BOOLar5k_ar5210_do_calibrate(struct ath_hal *hal, HAL_CHANNEL *channel){ /* * Enable calibration and wait until completion */ AR5K_REG_ENABLE_BITS(AR5K_AR5210_PHY_AGCCTL, AR5K_AR5210_PHY_AGCCTL_CAL); if (ar5k_register_timeout(hal, AR5K_AR5210_PHY_AGCCTL, AR5K_AR5210_PHY_AGCCTL_CAL, 0, AH_FALSE) == AH_FALSE) { AR5K_PRINTF("calibration timeout (%uMHz)\n", channel->c_channel); return (AH_FALSE); } return (AH_TRUE);}HAL_BOOLar5k_ar5210_noise_floor(struct ath_hal *hal, HAL_CHANNEL *channel){ int i; u_int32_t noise_floor; /* * Enable noise floor calibration and wait until completion */ AR5K_REG_ENABLE_BITS(AR5K_AR5210_PHY_AGCCTL, AR5K_AR5210_PHY_AGCCTL_NF); if (ar5k_register_timeout(hal, AR5K_AR5210_PHY_AGCCTL, AR5K_AR5210_PHY_AGCCTL_NF, 0, AH_FALSE) == AH_FALSE) { AR5K_PRINTF("noise floor calibration timeout (%uMHz)\n", channel->c_channel); return (AH_FALSE); } /* wait until the noise floor is calibrated */ for (i = 20; i > 0; i--) { AR5K_DELAY(1000); noise_floor = AR5K_REG_READ(AR5K_AR5210_PHY_NF); if (AR5K_AR5210_PHY_NF_RVAL(noise_floor) & AR5K_AR5210_PHY_NF_ACTIVE) noise_floor = AR5K_AR5210_PHY_NF_AVAL(noise_floor); if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) break; } if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { AR5K_PRINTF("noise floor calibration failed (%uMHz)\n", channel->c_channel); return (AH_FALSE); } return (AH_TRUE);}/* * Transmit functions */HAL_BOOLar5k_ar5210_update_tx_triglevel(struct ath_hal *hal, HAL_BOOL increase){ u_int32_t trigger_level; HAL_BOOL status = AH_FALSE; /* * Disable interrupts by setting the mask */ AR5K_REG_DISABLE_BITS(AR5K_AR5210_IMR, HAL_INT_GLOBAL); trigger_level = AR5K_REG_READ(AR5K_AR5210_TRIG_LVL); if (increase == AH_FALSE) { if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) goto done; } else { trigger_level += ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); } /* * Update trigger level on success */ AR5K_REG_WRITE(AR5K_AR5210_TRIG_LVL, trigger_level); status = AH_TRUE; done: /* * Restore interrupt mask */ AR5K_REG_ENABLE_BITS(AR5K_AR5210_IMR, HAL_INT_GLOBAL); return (status);}intar5k_ar5210_setup_tx_queue(struct ath_hal *hal, HAL_TX_QUEUE queue_type, const HAL_TXQ_INFO *queue_info){ u_int queue; /* * Get queue by type */ switch (queue_type) { case HAL_TX_QUEUE_DATA: queue = 0; break; case HAL_TX_QUEUE_BEACON: case HAL_TX_QUEUE_CAB: queue = 1; break; default: return (-1); } /* * Setup internal queue structure */ bzero(&hal->ah_txq[queue], sizeof(HAL_TXQ_INFO)); hal->ah_txq[queue].tqi_type = queue_type; if (queue_info != NULL) { if (ar5k_ar5210_setup_tx_queueprops(hal, queue, queue_info) != AH_TRUE) return (-1); } return (queue);}HAL_BOOLar5k_ar5210_setup_tx_queueprops(struct ath_hal *hal, int queue, const HAL_TXQ_INFO *queue_info){ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); if (hal->ah_txq[queue].tqi_type == HAL_TX_QUEUE_INACTIVE) return (AH_FALSE); hal->ah_txq[queue].tqi_aifs = queue_info->tqi_aifs; hal->ah_txq[queue].tqi_cw_max = queue_info->tqi_cw_max; hal->ah_txq[queue].tqi_cw_min = queue_info->tqi_cw_min; hal->ah_txq[queue].tqi_flags = queue_info->tqi_flags; return (AH_TRUE);}HAL_BOOL /*New*/ar5k_ar5210_get_tx_queueprops(struct ath_hal *hal, int queue, HAL_TXQ_INFO *queue_info){ AR5K_TRACE; memcpy(queue_info, &hal->ah_txq[queue], sizeof(HAL_TXQ_INFO)); return (AH_TRUE);}HAL_BOOLar5k_ar5210_release_tx_queue(struct ath_hal *hal, u_int queue){ AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); /* This queue will be skipped in further operations */ hal->ah_txq[queue].tqi_type = HAL_TX_QUEUE_INACTIVE; return (AH_FALSE);}voidar5k_ar5210_init_tx_queue(struct ath_hal *hal, u_int aifs, HAL_BOOL turbo){ int i; struct { u_int16_t mode_register; u_int32_t mode_base, mode_turbo; } initial[] = AR5K_AR5210_INI_MODE(aifs); /* * Write initial mode register settings */ for (i = 0; i < AR5K_ELEMENTS(initial); i++) AR5K_REG_WRITE((u_int32_t)initial[i].mode_register, turbo == AH_TRUE ? initial[i].mode_turbo : initial[i].mode_base);}HAL_BOOLar5k_ar5210_reset_tx_queue(struct ath_hal *hal, u_int queue){ u_int32_t cw_min, retry_lg, retry_sh; HAL_TXQ_INFO *tq; AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); tq = &hal->ah_txq[queue]; /* Only handle data queues, others will be ignored */ if (tq->tqi_type != HAL_TX_QUEUE_DATA) return (AH_TRUE); /* Set turbo/base mode parameters */ ar5k_ar5210_init_tx_queue(hal, hal->ah_aifs + tq->tqi_aifs, hal->ah_turbo == AH_TRUE ? AH_TRUE : AH_FALSE); /* * Set retry limits */ if (hal->ah_software_retry == AH_TRUE) { /* XXX Need to test this */ retry_lg = hal->ah_limit_tx_retries; retry_sh = retry_lg = retry_lg > AR5K_AR5210_RETRY_LMT_SH_RETRY ? AR5K_AR5210_RETRY_LMT_SH_RETRY : retry_lg; } else { retry_lg = AR5K_INIT_LG_RETRY; retry_sh = AR5K_INIT_SH_RETRY; } /* * Set initial content window (cw_min/cw_max) */ cw_min = 1; while (cw_min < hal->ah_cw_min) cw_min = (cw_min << 1) | 1; cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); /* Commit values */ AR5K_REG_WRITE(AR5K_AR5210_RETRY_LMT, (cw_min << AR5K_AR5210_RETRY_LMT_CW_MIN_S) | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, AR5K_AR5210_RETRY_LMT_SLG_RETRY) | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, AR5K_AR5210_RETRY_LMT_SSH_RETRY) | AR5K_REG_SM(retry_lg, AR5K_AR5210_RETRY_LMT_LG_RETRY) | AR5K_REG_SM(retry_sh, AR5K_AR5210_RETRY_LMT_SH_RETRY)); return (AH_TRUE);}u_int32_tar5k_ar5210_get_tx_buf(struct ath_hal *hal, u_int queue){ u_int16_t tx_reg; AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); /* * Get the transmit queue descriptor pointer register by type */ switch (hal->ah_txq[queue].tqi_type) { case HAL_TX_QUEUE_DATA: tx_reg = AR5K_AR5210_TXDP0; break; case HAL_TX_QUEUE_BEACON: case HAL_TX_QUEUE_CAB: tx_reg = AR5K_AR5210_TXDP1; break; default: return (0xffffffff); } return (AR5K_REG_READ(tx_reg));}HAL_BOOLar5k_ar5210_put_tx_buf(struct ath_hal *hal, u_int queue, u_int32_t phys_addr){ u_int16_t tx_reg; AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); /* * Get the transmit queue descriptor pointer register by type */ switch (hal->ah_txq[queue].tqi_type) { case HAL_TX_QUEUE_DATA: tx_reg = AR5K_AR5210_TXDP0; break; case HAL_TX_QUEUE_BEACON: case HAL_TX_QUEUE_CAB: tx_reg = AR5K_AR5210_TXDP1; break; default: return (AH_FALSE); } /* Set descriptor pointer */ AR5K_REG_WRITE(tx_reg, phys_addr); return (AH_TRUE);}u_int32_t /*Unimplemented*/ar5k_ar5210_num_tx_pending(struct ath_hal *hal, u_int queue) { AR5K_TRACE; return (AH_FALSE);}HAL_BOOLar5k_ar5210_tx_start(struct ath_hal *hal, u_int queue){ u_int32_t tx_queue; AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); tx_queue = AR5K_REG_READ(AR5K_AR5210_CR); /* * Set the queue type */ switch (hal->ah_txq[queue].tqi_type) { case HAL_TX_QUEUE_DATA: tx_queue |= AR5K_AR5210_CR_TXE0 & ~AR5K_AR5210_CR_TXD0; break; case HAL_TX_QUEUE_BEACON: tx_queue |= AR5K_AR5210_CR_TXE1 & ~AR5K_AR5210_CR_TXD1; AR5K_REG_WRITE(AR5K_AR5210_BSR, AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); break; case HAL_TX_QUEUE_CAB: tx_queue |= AR5K_AR5210_CR_TXE1 & ~AR5K_AR5210_CR_TXD1; AR5K_REG_WRITE(AR5K_AR5210_BSR, AR5K_AR5210_BCR_TQ1FV | AR5K_AR5210_BCR_TQ1V | AR5K_AR5210_BCR_BDMAE); break; default: return (AH_FALSE); } /* Start queue */ AR5K_REG_WRITE(AR5K_AR5210_CR, tx_queue); return (AH_TRUE);}HAL_BOOLar5k_ar5210_stop_tx_dma(struct ath_hal *hal, u_int queue){ u_int32_t tx_queue; AR5K_ASSERT_ENTRY(queue, hal->ah_capabilities.cap_queues.q_tx_num); tx_queue = AR5K_REG_READ(AR5K_AR5210_CR); /* * Set by queue type */ switch (hal->ah_txq[queue].tqi_type) { case HAL_TX_QUEUE_DATA: tx_queue |= AR5K_AR5210_CR_TXD0 & ~AR5K_AR5210_CR_TXE0; break; case HAL_TX_QUEUE_BEACON: case HAL_TX_QUEUE_CAB: /* XXX Fix me... */ tx_queue |= AR5K_AR5210_CR_TXD1 & ~AR5K_AR5210_CR_TXD1; AR5K_REG_WRITE(AR5K_AR5210_BSR, 0); break; default: return (AH_FALSE); } /* Stop queue */ AR5K_REG_WRITE(AR5K_AR5210_CR, tx_queue); return (AH_TRUE);}HAL_BOOL /*O.K. - Initialize tx_desc and clear ds_hw */ar5k_ar5210_setup_tx_desc(struct ath_hal *hal, struct ath_desc *desc, u_int packet_length, u_int header_length, HAL_PKT_TYPE type, u_int tx_power, u_int tx_rate0, u_int tx_tries0, u_int key_index, u_int antenna_mode, u_int flags, u_int rtscts_rate, u_int rtscts_duration){ u_int32_t frame_type; struct ar5k_ar5210_tx_desc *tx_desc; tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; /*Clear ds_hw*/ bzero(desc->ds_hw, sizeof(desc->ds_hw)); /* * Validate input */ if (tx_tries0 == 0) return (AH_FALSE); /* Initialize status descriptor */ tx_desc->tx_control_0 = 0; tx_desc->tx_control_1 = 0; /* Setup status descriptor */ if ((tx_desc->tx_control_0 = (packet_length & AR5K_AR5210_DESC_TX_CTL0_FRAME_LEN)) != packet_length) return (AH_FALSE); if ((tx_desc->tx_control_0 = (header_length & AR5K_AR5210_DESC_TX_CTL0_HEADER_LEN)) != header_length) return (AH_FALSE); if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP) frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_NO_DELAY; else if (type == HAL_PKT_TYPE_PIFS) frame_type = AR5K_AR5210_DESC_TX_FRAME_TYPE_PIFS; else frame_type = type; tx_desc->tx_control_0 = AR5K_REG_SM(frame_type, AR5K_AR5210_DESC_TX_CTL0_FRAME_TYPE); tx_desc->tx_control_0 |= AR5K_REG_SM(tx_rate0, AR5K_AR5210_DESC_TX_CTL0_XMIT_RATE);#define _TX_FLAGS(_c, _flag) \ if (flags & HAL_TXDESC_##_flag) \ tx_desc->tx_control_##_c |= \ AR5K_AR5210_DESC_TX_CTL##_c##_##_flag _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA);#undef _TX_FLAGS /* * WEP crap */ if (key_index != HAL_TXKEYIX_INVALID) { tx_desc->tx_control_0 |= AR5K_AR5210_DESC_TX_CTL0_ENCRYPT_KEY_VALID; tx_desc->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_AR5210_DESC_TX_CTL1_ENCRYPT_KEY_INDEX); } /* * RTS/CTS */ if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) { tx_desc->tx_control_1 |= rtscts_duration & AR5K_AR5210_DESC_TX_CTL1_RTS_DURATION; } return (AH_TRUE);}HAL_BOOL /*Added an argument *last_desc -need revision -don't clear descriptor here*/ar5k_ar5210_fill_tx_desc(struct ath_hal *hal, struct ath_desc *desc, u_int segment_length, HAL_BOOL first_segment, HAL_BOOL last_segment, const struct ath_desc *last_desc){ struct ar5k_ar5210_tx_desc *tx_desc; tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; /* Clear status descriptor */// bzero(desc->ds_hw, sizeof(desc->ds_hw)); /* Validate segment length and initialize the descriptor */ if ((tx_desc->tx_control_1 = (segment_length & AR5K_AR5210_DESC_TX_CTL1_BUF_LEN)) != segment_length) return (AH_FALSE); if (first_segment != AH_TRUE) tx_desc->tx_control_0 &= ~AR5K_AR5210_DESC_TX_CTL0_FRAME_LEN; if (last_segment != AH_TRUE) tx_desc->tx_control_1 |= AR5K_AR5210_DESC_TX_CTL1_MORE; return (AH_TRUE);}HAL_BOOLar5k_ar5210_setup_xtx_desc(struct ath_hal *hal, struct ath_desc *desc, u_int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, u_int tx_rate3, u_int tx_tries3){ /* * Does this function is for setting up XR? Not sure... * Nevertheless, I didn't find any information about XR support * by the AR5210. This seems to be a slightly new feature. */ return (AH_FALSE);}HAL_STATUSar5k_ar5210_proc_tx_desc(struct ath_hal *hal, struct ath_desc *desc){ struct ar5k_ar5210_tx_status *tx_status; struct ar5k_ar5210_tx_desc *tx_desc; tx_desc = (struct ar5k_ar5210_tx_desc*)&desc->ds_ctl0; tx_status = (struct ar5k_ar5210_tx_status*)&desc->ds_hw[0]; /* No frame has been send or error */ if ((tx_status->tx_status_1 & AR5K_AR5210_DESC_TX_STATUS1_DONE) == 0) return (HAL_EINPROGRESS); /* * Get descriptor status */ desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, AR5K_AR5210_DESC_TX_STATUS0_SEND_TIMESTAMP); desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_AR5210_DESC_TX_STATUS0_SHORT_RETRY_COUNT); desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_AR5210_DESC_TX_STATUS0_LONG_RETRY_COUNT); desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, AR5K_AR5210_DESC_TX_STATUS1_SEQ_NUM); desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, AR5K_AR5210_DESC_TX_STATUS1_ACK_SIG_STRENGTH); desc->ds_us.tx.ts_antenna = 1; desc->ds_us.tx.ts_status = 0; desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0, AR5K_AR5210_DESC_TX_CTL0_XMIT_RATE); if ((tx_status->tx_status_0 & AR5K_AR5210_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0) { if (tx_status->tx_status_0 & AR5K_AR5210_DESC_TX_STATUS0_EXCESSIVE_RETRIES) desc->ds_us.tx.ts_status |= HAL_TXERR_XRETRY; if (tx_status->tx_status_0 & AR5K_AR5210_DESC_TX_STATUS0_FIFO_UNDERRUN) desc->ds_us.tx.ts_status |= HAL_TXERR_FIFO; if (tx_status->tx_status_0 & AR5K_AR5210_DESC_TX_STATUS0_FILTERED) desc->ds_us.tx.ts_status |= HAL_TXERR_FILT; } return (HAL_OK);}HAL_BOOLar5k_ar5210_has_veol(struct ath_hal *hal){ return (AH_FALSE);}void /*Unimplemented*/ar5k_ar5210_get_tx_inter_queue(struct ath_hal *hal, u_int32_t *i){ AR5K_TRACE; /* XXX */ return;}/* * Receive functions */u_int32_tar5k_ar5210_get_rx_buf(struct ath_hal *hal){ return (AR5K_REG_READ(AR5K_AR5210_RXDP));}voidar5k_ar5210_put_rx_buf(struct ath_hal *hal, u_int32_t phys_addr){ AR5K_REG_WRITE(AR5K_AR5210_RXDP, phys_addr);}voidar5k_ar5210_start_rx(struct ath_hal *hal){ AR5K_REG_WRITE(AR5K_AR5210_CR, AR5K_AR5210_CR_RXE);}HAL_BOOLar5k_ar5210_stop_rx_dma(struct ath_hal *hal){ int i; AR5K_REG_WRITE(AR5K_AR5210_CR, AR5K_AR5210_CR_RXD); /* * It may take some time to disable the DMA receive unit */ for (i = 2000; i > 0 && (AR5K_REG_READ(AR5K_AR5210_CR) & AR5K_AR5210_CR_RXE) != 0; i--) AR5K_DELAY(10); return (i > 0 ? AH_TRUE : AH_FALSE);}voidar5k_ar5210_start_rx_pcu(struct ath_hal *hal){ AR5K_REG_DISABLE_BITS(AR5K_AR5210_DIAG_SW, AR5K_AR5210_DIAG_SW_DIS_RX);}voidar5k_ar5210_stop_pcu_recv(struct ath_hal *hal){ AR5K_REG_ENABLE_BITS(AR5K_AR5210_DIAG_SW, AR5K_AR5210_DIAG_SW_DIS_RX);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -