From d2c51456061354f83c15a457d8dc2d6c3d9bd213 Mon Sep 17 00:00:00 2001 From: stsp Date: Sat, 3 Feb 2024 10:03:18 +0000 Subject: [PATCH] implement qwx_tx() This gets the 4-way handshake working. Unfortunately, no traffic is passing yet, apparently because of CCMP decryption errors in Rx. --- sys/dev/ic/qwx.c | 519 +++++++++++++++++++++++++++++++++++++++++--- sys/dev/ic/qwxreg.h | 12 +- sys/dev/ic/qwxvar.h | 59 ++++- 3 files changed, 554 insertions(+), 36 deletions(-) diff --git a/sys/dev/ic/qwx.c b/sys/dev/ic/qwx.c index fcbe5ed64cc..85304096065 100644 --- a/sys/dev/ic/qwx.c +++ b/sys/dev/ic/qwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qwx.c,v 1.14 2024/02/02 15:44:19 stsp Exp $ */ +/* $OpenBSD: qwx.c,v 1.15 2024/02/03 10:03:18 stsp Exp $ */ /* * Copyright 2023 Stefan Sperling @@ -136,6 +136,8 @@ int qwx_mac_start(struct qwx_softc *); void qwx_mac_scan_finish(struct qwx_softc *); int qwx_mac_mgmt_tx_wmi(struct qwx_softc *, struct qwx_vif *, uint8_t, struct mbuf *); +int qwx_dp_tx(struct qwx_softc *, struct qwx_vif *, uint8_t, + struct ieee80211_node *, struct mbuf *); int qwx_dp_tx_send_reo_cmd(struct qwx_softc *, struct dp_rx_tid *, enum hal_reo_cmd_type , struct ath11k_hal_reo_cmd *, void (*func)(struct qwx_dp *, void *, enum hal_reo_cmd_status)); @@ -358,9 +360,7 @@ qwx_tx(struct qwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (frame_type == IEEE80211_FC0_TYPE_MGT) return qwx_mac_mgmt_tx_wmi(sc, arvif, pdev_id, m); - printf("%s: not implemented\n", __func__); - m_freem(m); - return ENOTSUP; + return qwx_dp_tx(sc, arvif, pdev_id, ni, m); } void @@ -1455,10 +1455,38 @@ qwx_hw_wcn6855_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) return desc->u.wcn6855.mpdu_start.addr2; } +/* Map from pdev index to hw mac index */ +uint8_t +qwx_hw_ipq8074_mac_from_pdev_id(int pdev_idx) +{ + switch (pdev_idx) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + default: + return ATH11K_INVALID_HW_MAC_ID; + } +} + +uint8_t qwx_hw_ipq6018_mac_from_pdev_id(int pdev_idx) +{ + return pdev_idx; +} + +static inline int +qwx_hw_get_mac_from_pdev_id(struct qwx_softc *sc, int pdev_idx) +{ + if (sc->hw_params.hw_ops->get_hw_mac_from_pdev_id) + return sc->hw_params.hw_ops->get_hw_mac_from_pdev_id(pdev_idx); + + return 0; +} + const struct ath11k_hw_ops ipq8074_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_ipq8074, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_ipq8074, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_ipq8074, @@ -1510,9 +1538,7 @@ const struct ath11k_hw_ops ipq8074_ops = { }; const struct ath11k_hw_ops ipq6018_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq6018_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_ipq8074, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_ipq8074, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_ipq8074, @@ -1564,9 +1590,7 @@ const struct ath11k_hw_ops ipq6018_ops = { }; const struct ath11k_hw_ops qca6390_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_qca6390, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_qca6390, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_qca6390, @@ -1618,13 +1642,11 @@ const struct ath11k_hw_ops qca6390_ops = { }; const struct ath11k_hw_ops qcn9074_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq6018_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_ipq8074, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_ipq8074, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_ipq8074, -#ifdef notyet +#if notyet .tx_mesh_enable = ath11k_hw_qcn9074_tx_mesh_enable, .rx_desc_get_first_msdu = ath11k_hw_qcn9074_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath11k_hw_qcn9074_rx_desc_get_last_msdu, @@ -1672,13 +1694,11 @@ const struct ath11k_hw_ops qcn9074_ops = { }; const struct ath11k_hw_ops wcn6855_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_qca6390, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_qca6390, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_qca6390, -#ifdef notyet +#if notyet .tx_mesh_enable = ath11k_hw_wcn6855_tx_mesh_enable, .rx_desc_get_first_msdu = ath11k_hw_wcn6855_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath11k_hw_wcn6855_rx_desc_get_last_msdu, @@ -1726,9 +1746,7 @@ const struct ath11k_hw_ops wcn6855_ops = { }; const struct ath11k_hw_ops wcn6750_ops = { -#if notyet - .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, -#endif + .get_hw_mac_from_pdev_id = qwx_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = qwx_init_wmi_config_qca6390, .mac_id_to_pdev_id = qwx_hw_mac_id_to_pdev_id_qca6390, .mac_id_to_srng_id = qwx_hw_mac_id_to_srng_id_qca6390, @@ -3052,7 +3070,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .sram_dump = {}, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3139,7 +3159,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .sram_dump = {}, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3228,7 +3250,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3316,7 +3340,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .sram_dump = {}, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3405,7 +3431,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3493,7 +3521,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .tcl_ring_retry = true, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE, +#ifdef notyet .smp2p_wow_exit = false, #endif }, @@ -3578,7 +3608,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .sram_dump = {}, .tcl_ring_retry = false, +#endif .tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750, +#ifdef notyet .smp2p_wow_exit = true, #endif }, @@ -9953,6 +9985,51 @@ qwx_dp_link_desc_cleanup(struct qwx_softc *sc, } } +void +qwx_dp_tx_ring_free_tx_data(struct qwx_softc *sc, struct dp_tx_ring *tx_ring) +{ + int i; + + if (tx_ring->data == NULL) + return; + + for (i = 0; i < sc->hw_params.tx_ring_size; i++) { + struct qwx_tx_data *tx_data = &tx_ring->data[i]; + + if (tx_data->map) { + bus_dmamap_unload(sc->sc_dmat, tx_data->map); + bus_dmamap_destroy(sc->sc_dmat, tx_data->map); + } + + m_freem(tx_data->m); + } + + free(tx_ring->data, M_DEVBUF, + sc->hw_params.tx_ring_size * sizeof(struct qwx_tx_data)); + tx_ring->data = NULL; +} + +int +qwx_dp_tx_ring_alloc_tx_data(struct qwx_softc *sc, struct dp_tx_ring *tx_ring) +{ + int i, ret; + + tx_ring->data = mallocarray(sc->hw_params.tx_ring_size, + sizeof(struct qwx_tx_data), M_DEVBUF, M_NOWAIT | M_ZERO); + if (tx_ring->data == NULL) + return ENOMEM; + + for (i = 0; i < sc->hw_params.tx_ring_size; i++) { + struct qwx_tx_data *tx_data = &tx_ring->data[i]; + + ret = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, + BUS_DMA_NOWAIT, &tx_data->map); + if (ret) + return ret; + } + + return 0; +} int qwx_dp_alloc(struct qwx_softc *sc) @@ -10003,8 +10080,13 @@ qwx_dp_alloc(struct qwx_softc *sc) idr_init(&dp->tx_ring[i].txbuf_idr); spin_lock_init(&dp->tx_ring[i].tx_idr_lock); #endif - dp->tx_ring[i].tcl_data_ring_id = i; + ret = qwx_dp_tx_ring_alloc_tx_data(sc, &dp->tx_ring[i]); + if (ret) + goto fail_cmn_srng_cleanup; + dp->tx_ring[i].cur = 0; + dp->tx_ring[i].queued = 0; + dp->tx_ring[i].tcl_data_ring_id = i; dp->tx_ring[i].tx_status_head = 0; dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1; dp->tx_ring[i].tx_status = malloc(size, M_DEVBUF, @@ -10051,6 +10133,7 @@ qwx_dp_free(struct qwx_softc *sc) idr_destroy(&dp->tx_ring[i].txbuf_idr); spin_unlock_bh(&dp->tx_ring[i].tx_idr_lock); #endif + qwx_dp_tx_ring_free_tx_data(sc, &dp->tx_ring[i]); free(dp->tx_ring[i].tx_status, M_DEVBUF, sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE); dp->tx_ring[i].tx_status = NULL; @@ -14544,9 +14627,146 @@ qwx_dp_vdev_tx_attach(struct qwx_softc *sc, struct qwx_pdev *pdev, qwx_dp_update_vdev_search(sc, arvif); } +void +qwx_dp_tx_status_parse(struct qwx_softc *sc, struct hal_wbm_release_ring *desc, + struct hal_tx_status *ts) +{ + ts->buf_rel_source = FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, + desc->info0); + if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && + ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) + return; + + if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) + return; + + ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, + desc->info0); + ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER, + desc->info1); + ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT, + desc->info1); + ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI, + desc->info2); + if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU) + ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU; + ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3); + ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3); + if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID) + ts->rate_stats = desc->rate_stats.info0; + else + ts->rate_stats = 0; +} + +void +qwx_dp_tx_process_htt_tx_complete(struct qwx_softc *sc, void *desc, + uint8_t mac_id, uint32_t msdu_id, struct dp_tx_ring *tx_ring) +{ + printf("%s: not implemented\n", __func__); +} + +void +qwx_dp_tx_complete_msdu(struct qwx_softc *sc, struct dp_tx_ring *tx_ring, + uint32_t msdu_id, struct hal_tx_status *ts) +{ + struct qwx_tx_data *tx_data = &tx_ring->data[msdu_id]; + + if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) { + /* Must not happen */ + return; + } + + bus_dmamap_unload(sc->sc_dmat, tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + + /* TODO: Tx rate adjustment? */ + + if (tx_ring->queued > 0) + tx_ring->queued--; +} + +#define QWX_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) + int qwx_dp_tx_completion_handler(struct qwx_softc *sc, int ring_id) { + struct qwx_dp *dp = &sc->dp; + int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; + struct hal_srng *status_ring = &sc->hal.srng_list[hal_ring_id]; + struct hal_tx_status ts = { 0 }; + struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; + uint32_t *desc; + uint32_t msdu_id; + uint8_t mac_id; +#ifdef notyet + spin_lock_bh(&status_ring->lock); +#endif + qwx_hal_srng_access_begin(sc, status_ring); + + while ((QWX_TX_COMPL_NEXT(tx_ring->tx_status_head) != + tx_ring->tx_status_tail) && + (desc = qwx_hal_srng_dst_get_next_entry(sc, status_ring))) { + memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], desc, + sizeof(struct hal_wbm_release_ring)); + tx_ring->tx_status_head = + QWX_TX_COMPL_NEXT(tx_ring->tx_status_head); + } +#if 0 + if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && + (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == + tx_ring->tx_status_tail))) { + /* TODO: Process pending tx_status messages when kfifo_is_full() */ + ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); + } +#endif + qwx_hal_srng_access_end(sc, status_ring); +#ifdef notyet + spin_unlock_bh(&status_ring->lock); +#endif + while (QWX_TX_COMPL_NEXT(tx_ring->tx_status_tail) != + tx_ring->tx_status_head) { + struct hal_wbm_release_ring *tx_status; + uint32_t desc_id; + + tx_ring->tx_status_tail = + QWX_TX_COMPL_NEXT(tx_ring->tx_status_tail); + tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; + qwx_dp_tx_status_parse(sc, tx_status, &ts); + + desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, + tx_status->buf_addr_info.info1); + mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); + if (mac_id >= MAX_RADIOS) + continue; + msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); + if (msdu_id >= sc->hw_params.tx_ring_size) + continue; + + if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { + qwx_dp_tx_process_htt_tx_complete(sc, + (void *)tx_status, mac_id, msdu_id, tx_ring); + continue; + } +#if 0 + spin_lock(&tx_ring->tx_idr_lock); + msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); + if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); + spin_unlock(&tx_ring->tx_idr_lock); + continue; + } + + spin_unlock(&tx_ring->tx_idr_lock); + ar = ab->pdevs[mac_id].ar; + + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); +#endif + qwx_dp_tx_complete_msdu(sc, tx_ring, msdu_id, &ts); + } + return 0; } @@ -21050,6 +21270,7 @@ int qwx_peer_create(struct qwx_softc *sc, struct qwx_vif *arvif, uint8_t pdev_id, struct ieee80211_node *ni, struct peer_create_params *param) { + struct ieee80211com *ic = &sc->sc_ic; struct qwx_node *nq = (struct qwx_node *)ni; struct ath11k_peer *peer; int ret; @@ -21131,11 +21352,12 @@ qwx_peer_create(struct qwx_softc *sc, struct qwx_vif *arvif, uint8_t pdev_id, peer->pdev_id = pdev_id; #if 0 peer->sta = sta; - - if (arvif->vif->type == NL80211_IFTYPE_STATION) { +#endif + if (ic->ic_opmode == IEEE80211_M_STA) { arvif->ast_hash = peer->ast_hash; arvif->ast_idx = peer->hw_peer_id; } +#if 0 peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; @@ -21715,6 +21937,249 @@ peer_clean: return ret; } +enum hal_tcl_encap_type +qwx_dp_tx_get_encap_type(struct qwx_softc *sc) +{ + if (test_bit(ATH11K_FLAG_RAW_MODE, sc->sc_flags)) + return HAL_TCL_ENCAP_TYPE_RAW; +#if 0 + if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) + return HAL_TCL_ENCAP_TYPE_ETHERNET; +#endif + return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI; +} + +uint8_t +qwx_dp_tx_get_tid(struct mbuf *m) +{ + struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); + uint16_t qos = ieee80211_get_qos(wh); + uint8_t tid = qos & IEEE80211_QOS_TID; + + return tid; +} + +void +qwx_hal_tx_cmd_desc_setup(struct qwx_softc *sc, void *cmd, + struct hal_tx_info *ti) +{ + struct hal_tcl_data_cmd *tcl_cmd = (struct hal_tcl_data_cmd *)cmd; + + tcl_cmd->buf_addr_info.info0 = FIELD_PREP(BUFFER_ADDR_INFO0_ADDR, + ti->paddr); + tcl_cmd->buf_addr_info.info1 = FIELD_PREP(BUFFER_ADDR_INFO1_ADDR, + ((uint64_t)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT)); + tcl_cmd->buf_addr_info.info1 |= FIELD_PREP( + BUFFER_ADDR_INFO1_RET_BUF_MGR, ti->rbm_id) | + FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, ti->desc_id); + + tcl_cmd->info0 = + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_DESC_TYPE, ti->type) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ENCAP_TYPE, ti->encap_type) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ENCRYPT_TYPE, ti->encrypt_type) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_SEARCH_TYPE, ti->search_type) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ADDR_EN, ti->addr_search_flags) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_CMD_NUM, ti->meta_data_flags); + + tcl_cmd->info1 = ti->flags0 | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_DATA_LEN, ti->data_len) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_PKT_OFFSET, ti->pkt_offset); + + tcl_cmd->info2 = ti->flags1 | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID, ti->tid) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_LMAC_ID, ti->lmac_id); + + tcl_cmd->info3 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_DSCP_TID_TABLE_IDX, + ti->dscp_tid_tbl_idx) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_SEARCH_INDEX, ti->bss_ast_idx) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_CACHE_SET_NUM, ti->bss_ast_hash); + tcl_cmd->info4 = 0; +#ifdef notyet + if (ti->enable_mesh) + ab->hw_params.hw_ops->tx_mesh_enable(ab, tcl_cmd); +#endif +} + +int +qwx_dp_tx(struct qwx_softc *sc, struct qwx_vif *arvif, uint8_t pdev_id, + struct ieee80211_node *ni, struct mbuf *m) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct qwx_dp *dp = &sc->dp; + struct hal_tx_info ti = {0}; + struct qwx_tx_data *tx_data; + struct hal_srng *tcl_ring; + struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); + struct ieee80211_key *k = NULL; + struct dp_tx_ring *tx_ring; + void *hal_tcl_desc; + uint8_t pool_id; + uint8_t hal_ring_id; + int ret, msdu_id; + uint32_t ring_selector = 0; + uint8_t ring_map = 0; + + if (test_bit(ATH11K_FLAG_CRASH_FLUSH, sc->sc_flags)) { + m_freem(m); + printf("%s: crash flush\n", __func__); + return ESHUTDOWN; + } +#if 0 + if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + !ieee80211_is_data(hdr->frame_control))) + return -ENOTSUPP; +#endif + pool_id = 0; + ring_selector = 0; + + ti.ring_id = ring_selector % sc->hw_params.max_tx_ring; + ti.rbm_id = sc->hw_params.hal_params->tcl2wbm_rbm_map[ti.ring_id].rbm_id; + + ring_map |= (1 << ti.ring_id); + + tx_ring = &dp->tx_ring[ti.ring_id]; + + if (tx_ring->queued >= sc->hw_params.tx_ring_size) { + m_freem(m); + return ENOSPC; + } + + msdu_id = tx_ring->cur; + tx_data = &tx_ring->data[msdu_id]; + if (tx_data->m != NULL) { + m_freem(m); + return ENOSPC; + } + + ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, pdev_id) | + FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, msdu_id) | + FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id); + ti.encap_type = qwx_dp_tx_get_encap_type(sc); + + ti.meta_data_flags = arvif->tcl_metadata; + + if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { +#if 0 + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { + ti.encrypt_type = + ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); + + if (ieee80211_has_protected(hdr->frame_control)) + skb_put(skb, IEEE80211_CCMP_MIC_LEN); + } else +#endif + ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; + + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_get_txkey(ic, wh, ni); + if ((m = ieee80211_encrypt(ic, m, k)) == NULL) { + printf("%s: encrypt failed\n", __func__); + return ENOBUFS; + } + /* 802.11 header may have moved. */ + wh = mtod(m, struct ieee80211_frame *); + } + } + + ti.addr_search_flags = arvif->hal_addr_search_flags; + ti.search_type = arvif->search_type; + ti.type = HAL_TCL_DESC_TYPE_BUFFER; + ti.pkt_offset = 0; + ti.lmac_id = qwx_hw_get_mac_from_pdev_id(sc, pdev_id); + ti.bss_ast_hash = arvif->ast_hash; + ti.bss_ast_idx = arvif->ast_idx; + ti.dscp_tid_tbl_idx = 0; +#if 0 + if (likely(skb->ip_summed == CHECKSUM_PARTIAL && + ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) { + ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN, 1); + } + + if (ieee80211_vif_is_mesh(arvif->vif)) + ti.enable_mesh = true; +#endif + ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1); + + ti.tid = qwx_dp_tx_get_tid(m); +#if 0 + switch (ti.encap_type) { + case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI: + ath11k_dp_tx_encap_nwifi(skb); + break; + case HAL_TCL_ENCAP_TYPE_RAW: + if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { + ret = -EINVAL; + goto fail_remove_idr; + } + break; + case HAL_TCL_ENCAP_TYPE_ETHERNET: + /* no need to encap */ + break; + case HAL_TCL_ENCAP_TYPE_802_3: + default: + /* TODO: Take care of other encap modes as well */ + ret = -EINVAL; + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + goto fail_remove_idr; + } +#endif + ret = bus_dmamap_load_mbuf(sc->sc_dmat, tx_data->map, + m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); + if (ret) { + printf("%s: failed to map Tx buffer: %d\n", + sc->sc_dev.dv_xname, ret); + m_freem(m); + return ret; + } + ti.paddr = tx_data->map->dm_segs[0].ds_addr; + + ti.data_len = m->m_pkthdr.len; + + hal_ring_id = tx_ring->tcl_data_ring.ring_id; + tcl_ring = &sc->hal.srng_list[hal_ring_id]; +#ifdef notyet + spin_lock_bh(&tcl_ring->lock); +#endif + qwx_hal_srng_access_begin(sc, tcl_ring); + + hal_tcl_desc = (void *)qwx_hal_srng_src_get_next_entry(sc, tcl_ring); + if (!hal_tcl_desc) { + printf("%s: hal_tcl_desc == NULL\n", __func__); + /* NOTE: It is highly unlikely we'll be running out of tcl_ring + * desc because the desc is directly enqueued onto hw queue. + */ + qwx_hal_srng_access_end(sc, tcl_ring); +#if 0 + ab->soc_stats.tx_err.desc_na[ti.ring_id]++; +#endif +#ifdef notyet + spin_unlock_bh(&tcl_ring->lock); +#endif + bus_dmamap_unload(sc->sc_dmat, tx_data->map); + m_freem(m); + return ENOMEM; + } + + tx_data->m = m; + + qwx_hal_tx_cmd_desc_setup(sc, + hal_tcl_desc + sizeof(struct hal_tlv_hdr), &ti); + + qwx_hal_srng_access_end(sc, tcl_ring); + + qwx_dp_shadow_start_timer(sc, tcl_ring, &dp->tx_ring_timer[ti.ring_id]); +#ifdef notyet + spin_unlock_bh(&tcl_ring->lock); +#endif + tx_ring->queued++; + tx_ring->cur = (tx_ring->cur + 1) % sc->hw_params.tx_ring_size; + return 0; +} + int qwx_mac_station_add(struct qwx_softc *sc, struct qwx_vif *arvif, uint8_t pdev_id, struct ieee80211_node *ni) diff --git a/sys/dev/ic/qwxreg.h b/sys/dev/ic/qwxreg.h index eda52898ae8..3871df9c7b0 100644 --- a/sys/dev/ic/qwxreg.h +++ b/sys/dev/ic/qwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxreg.h,v 1.5 2024/02/02 15:44:19 stsp Exp $ */ +/* $OpenBSD: qwxreg.h,v 1.6 2024/02/03 10:03:18 stsp Exp $ */ /* * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. @@ -38,6 +38,16 @@ * core.h */ +#define ATH11K_TX_MGMT_NUM_PENDING_MAX 512 + +#define ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI 64 + +/* Pending management packets threshold for dropping probe responses */ +#define ATH11K_PRB_RSP_DROP_THRESHOLD ((ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI * 3) / 4) + +#define ATH11K_INVALID_HW_MAC_ID 0xFF +#define ATH11K_CONNECTION_LOSS_HZ (3 * HZ) + enum ath11k_hw_rev { ATH11K_HW_IPQ8074, ATH11K_HW_QCA6390_HW20, diff --git a/sys/dev/ic/qwxvar.h b/sys/dev/ic/qwxvar.h index 4a39cf1e4fe..67a951f3527 100644 --- a/sys/dev/ic/qwxvar.h +++ b/sys/dev/ic/qwxvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxvar.h,v 1.9 2024/02/02 15:44:19 stsp Exp $ */ +/* $OpenBSD: qwxvar.h,v 1.10 2024/02/03 10:03:18 stsp Exp $ */ /* * Copyright (c) 2018-2019 The Linux Foundation. @@ -113,6 +113,53 @@ struct ath11k_hw_hal_params { const struct ath11k_hw_tcl2wbm_rbm_map *tcl2wbm_rbm_map; }; +struct hal_tx_info { + uint16_t meta_data_flags; /* %HAL_TCL_DATA_CMD_INFO0_META_ */ + uint8_t ring_id; + uint32_t desc_id; + enum hal_tcl_desc_type type; + enum hal_tcl_encap_type encap_type; + uint64_t paddr; + uint32_t data_len; + uint32_t pkt_offset; + enum hal_encrypt_type encrypt_type; + uint32_t flags0; /* %HAL_TCL_DATA_CMD_INFO1_ */ + uint32_t flags1; /* %HAL_TCL_DATA_CMD_INFO2_ */ + uint16_t addr_search_flags; /* %HAL_TCL_DATA_CMD_INFO0_ADDR(X/Y)_ */ + uint16_t bss_ast_hash; + uint16_t bss_ast_idx; + uint8_t tid; + uint8_t search_type; /* %HAL_TX_ADDR_SEARCH_ */ + uint8_t lmac_id; + uint8_t dscp_tid_tbl_idx; + bool enable_mesh; + uint8_t rbm_id; +}; + +/* TODO: Check if the actual desc macros can be used instead */ +#define HAL_TX_STATUS_FLAGS_FIRST_MSDU BIT(0) +#define HAL_TX_STATUS_FLAGS_LAST_MSDU BIT(1) +#define HAL_TX_STATUS_FLAGS_MSDU_IN_AMSDU BIT(2) +#define HAL_TX_STATUS_FLAGS_RATE_STATS_VALID BIT(3) +#define HAL_TX_STATUS_FLAGS_RATE_LDPC BIT(4) +#define HAL_TX_STATUS_FLAGS_RATE_STBC BIT(5) +#define HAL_TX_STATUS_FLAGS_OFDMA BIT(6) + +#define HAL_TX_STATUS_DESC_LEN sizeof(struct hal_wbm_release_ring) + +/* Tx status parsed from srng desc */ +struct hal_tx_status { + enum hal_wbm_rel_src_module buf_rel_source; + enum hal_wbm_tqm_rel_reason status; + uint8_t ack_rssi; + uint32_t flags; /* %HAL_TX_STATUS_FLAGS_ */ + uint32_t ppdu_id; + uint8_t try_cnt; + uint8_t tid; + uint16_t peer_id; + uint32_t rate_stats; +}; + struct ath11k_hw_params { const char *name; uint16_t hw_rev; @@ -209,9 +256,7 @@ struct ath11k_hw_params { }; struct ath11k_hw_ops { -#if notyet uint8_t (*get_hw_mac_from_pdev_id)(int pdev_id); -#endif void (*wmi_init_config)(struct qwx_softc *sc, struct target_resource_config *config); int (*mac_id_to_pdev_id)(struct ath11k_hw_params *hw, int mac_id); @@ -922,11 +967,9 @@ struct dp_tx_ring { uint8_t tcl_data_ring_id; struct dp_srng tcl_data_ring; struct dp_srng tcl_comp_ring; -#if 0 - struct idr txbuf_idr; - /* Protects txbuf_idr and num_pending */ - spinlock_t tx_idr_lock; -#endif + int cur; + int queued; + struct qwx_tx_data *data; struct hal_wbm_release_ring *tx_status; int tx_status_head; int tx_status_tail; -- 2.20.1