diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index fd5ed3973a..d32d58b551 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -401,7 +401,17 @@ struct cdp_soc_t { struct ol_if_ops *ol_ops; }; - +/* + * cdp_vdev_param_type: different types of parameters + * to set values in vdev + * @CDP_ENABLE_NAWDS: set nawds enable/disable + * @CDP_ENABLE_MCAST_EN: enable/disable multicast enhancement + * + */ +enum cdp_vdev_param_type { + CDP_ENABLE_NAWDS, + CDP_ENABLE_MCAST_EN, +}; #define TXRX_FW_STATS_TXSTATS 1 #define TXRX_FW_STATS_RXSTATS 2 diff --git a/dp/inc/cdp_txrx_ctrl.h b/dp/inc/cdp_txrx_ctrl.h index 8a7023a031..f0018cc571 100644 --- a/dp/inc/cdp_txrx_ctrl.h +++ b/dp/inc/cdp_txrx_ctrl.h @@ -288,4 +288,22 @@ static inline void cdp_tx_flush_buffers return; } +static inline void cdp_txrx_set_vdev_param(ol_txrx_soc_handle soc, + struct cdp_vdev *vdev, enum cdp_vdev_param_type type, + uint32_t val) +{ + if (soc->ops->ctrl_ops->txrx_set_vdev_param) + return soc->ops->ctrl_ops->txrx_set_vdev_param(vdev, type, val); + return; +} + +static inline void +cdp_peer_set_nawds(ol_txrx_soc_handle soc, + struct ol_txrx_peer_t *peer, uint8_t value) +{ + if (soc->ops->ctrl_ops->txrx_peer_set_nawds) + return soc->ops->ctrl_ops->txrx_peer_set_nawds + (peer, value); + return; +} #endif diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index f0f4199cc4..51112ee7bd 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -359,6 +359,10 @@ struct cdp_ctrl_ops { int (*txrx_is_target_ar900b)(struct cdp_vdev *vdev); + void (*txrx_set_vdev_param)(struct cdp_vdev *vdev, + enum cdp_vdev_param_type param, uint32_t val); + + void (*txrx_peer_set_nawds)(void *peer, uint8_t value); }; struct cdp_me_ops { @@ -557,6 +561,7 @@ struct ol_if_ops { struct cdp_lro_hash_config *lro_hash); void (*update_dp_stats)(void *soc, void *stats, uint16_t id, uint8_t type); + uint8_t (*rx_invalid_peer)(void *osif_pdev, void *msg); /* TODO: Add any other control path calls required to OL_IF/WMA layer */ }; diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 7a68c92334..799b2746a9 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -2960,6 +2960,38 @@ dp_get_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr) dp_print_peer_stats(peer); return; } +/* + * dp_set_vdev_param: function to set parameters in vdev + * @param: parameter type to be set + * @val: value of parameter to be set + * + * return: void + */ +static void dp_set_vdev_param(struct cdp_vdev *vdev_handle, + enum cdp_vdev_param_type param, uint32_t val) +{ + struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle; + + switch (param) { + case CDP_ENABLE_NAWDS: + vdev->nawds_enabled = val; + default: + break; + } +} + +/** + * dp_peer_set_nawds: set nawds bit in peer + * @peer_handle: pointer to peer + * @value: enable/disable nawds + * + * return: void + */ +static void dp_peer_set_nawds(void *peer_handle, uint8_t value) +{ + struct dp_peer *peer = (struct dp_peer *)peer_handle; + peer->nawds_enabled = value; +} /* * dp_set_vdev_dscp_tid_map_wifi3(): Update Map ID selected for particular vdev @@ -3065,6 +3097,8 @@ static struct cdp_ctrl_ops dp_ops_ctrl = { .txrx_set_mesh_mode = dp_peer_set_mesh_mode, .txrx_set_mesh_rx_filter = dp_peer_set_mesh_rx_filter, #endif + .txrx_set_vdev_param = dp_set_vdev_param, + .txrx_peer_set_nawds = dp_peer_set_nawds, /* TODO: Add other functions */ }; diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index f9b65e3d9f..939b039ff3 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -495,6 +495,78 @@ QDF_STATUS dp_rx_filter_mesh_packets(struct dp_vdev *vdev, qdf_nbuf_t nbuf) #endif +#ifdef CONFIG_WIN +/** + * dp_rx_process_invalid_peer(): Function to pass invalid peer list to umac + * @soc: DP SOC handle + * @nbuf: nbuf for which peer is invalid + * + * return: integer type + */ +uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf) +{ + struct dp_invalid_peer_msg msg; + struct dp_vdev *vdev = NULL; + struct dp_pdev *pdev = NULL; + struct ieee80211_frame *wh; + uint8_t i; + uint8_t *rx_pkt_hdr; + + rx_pkt_hdr = qdf_nbuf_data(nbuf); + wh = (struct ieee80211_frame *)rx_pkt_hdr; + + if (!DP_FRAME_IS_DATA(wh)) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, + "NAWDS valid only for data frames"); + return 1; + } + + if (qdf_nbuf_len(nbuf) < sizeof(struct ieee80211_frame)) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "Invalid nbuf length"); + return 1; + } + + + for (i = 0; i < MAX_PDEV_CNT; i++) { + pdev = soc->pdev_list[i]; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "PDEV not found"); + continue; + } + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_mem_cmp(wh->i_addr1, vdev->mac_addr.raw, + DP_MAC_ADDR_LEN) == 0) { + goto out; + } + } + } + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "VDEV not found"); + return 1; + } + +out: + msg.wh = wh; + msg.nbuf = nbuf; + msg.vdev_id = vdev->vdev_id; + if (pdev->soc->cdp_soc.ol_ops->rx_invalid_peer) + return pdev->soc->cdp_soc.ol_ops->rx_invalid_peer( + pdev->osif_pdev, &msg); + + return 0; +} +#else +uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf) +{ + return 0; +} +#endif + /** * dp_rx_process() - Brain of the Rx processing functionality * Called from the bottom half (tasklet/NET_RX_SOFTIRQ) @@ -717,6 +789,7 @@ done: /* Peer lookup failed */ if (!peer && !vdev) { + dp_rx_process_invalid_peer(soc, nbuf); /* Drop & free packet */ qdf_nbuf_free(nbuf); diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 90a8e152bf..4cc2b515e8 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -256,6 +256,7 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc, } #endif +uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf); #define DP_RX_LIST_APPEND(head, tail, elem) \ do { \ if (!(head)) { \ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index b8156297d2..fcd5319c39 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -274,7 +274,8 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, if (!peer) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, FL("peer is NULL")); - qdf_nbuf_free(nbuf); + qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); + dp_rx_process_invalid_peer(soc, nbuf); goto fail; } diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 11eb3d6d3d..d290d2d4f7 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -830,20 +830,23 @@ static void dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf, * @nbuf: skb * @tid: TID from HLOS for overriding default DSCP-TID mapping * @tx_q: Tx queue to be used for this Tx frame + * @peer_id: peer_id of the peer in case of NAWDS frames * * Return: NULL on success, * nbuf when it fails to send */ static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, uint8_t tid, struct dp_tx_queue *tx_q, - uint32_t *meta_data) + uint32_t *meta_data, uint16_t peer_id) { struct dp_pdev *pdev = vdev->pdev; struct dp_soc *soc = pdev->soc; struct dp_tx_desc_s *tx_desc; QDF_STATUS status; void *hal_srng = soc->tcl_data_ring[tx_q->ring_id].hal_srng; + uint16_t htt_tcl_metadata = 0; + HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 0); /* Setup Tx descriptor for an MSDU, and MSDU extension descriptor */ tx_desc = dp_tx_prepare_desc_single(vdev, nbuf, tx_q->desc_pool_id, meta_data); if (!tx_desc) { @@ -862,9 +865,17 @@ static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, goto fail_return; } + if (qdf_unlikely(peer_id != HTT_INVALID_PEER)) { + HTT_TX_TCL_METADATA_TYPE_SET(htt_tcl_metadata, + HTT_TCL_METADATA_TYPE_PEER_BASED); + HTT_TX_TCL_METADATA_PEER_ID_SET(htt_tcl_metadata, + peer_id); + } else + htt_tcl_metadata = vdev->htt_tcl_metadata; + /* Enqueue the Tx MSDU descriptor to HW for transmit */ status = dp_tx_hw_enqueue(soc, vdev, tx_desc, tid, - vdev->htt_tcl_metadata, tx_q->ring_id); + htt_tcl_metadata, tx_q->ring_id); if (status != QDF_STATUS_SUCCESS) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, @@ -1160,6 +1171,49 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf, #endif +/** + * dp_tx_prepare_nawds(): Tramit NAWDS frames + * @vdev: dp_vdev handle + * @nbuf: skb + * @tid: TID from HLOS for overriding default DSCP-TID mapping + * @tx_q: Tx queue to be used for this Tx frame + * @meta_data: Meta date for mesh + * @peer_id: peer_id of the peer in case of NAWDS frames + * + * return: NULL on success nbuf on failure + */ +static qdf_nbuf_t dp_tx_prepare_nawds(struct dp_vdev *vdev, qdf_nbuf_t nbuf, + uint8_t tid, struct dp_tx_queue *tx_q, uint32_t *meta_data, + uint32_t peer_id) +{ + struct dp_peer *peer = NULL; + qdf_nbuf_t nbuf_copy; + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + if ((peer->peer_ids[0] != HTT_INVALID_PEER) && + (peer->nawds_enabled || peer->bss_peer)) { + nbuf_copy = qdf_nbuf_copy(nbuf); + if (!nbuf_copy) { + QDF_TRACE(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_ERROR, + "nbuf copy failed"); + } + + peer_id = peer->peer_ids[0]; + nbuf_copy = dp_tx_send_msdu_single(vdev, nbuf_copy, tid, + tx_q, meta_data, peer_id); + if (nbuf_copy != NULL) { + qdf_nbuf_free(nbuf); + return nbuf_copy; + } + } + } + if (peer_id == HTT_INVALID_PEER) + return nbuf; + + qdf_nbuf_free(nbuf); + return NULL; +} + /** * dp_tx_send() - Transmit a frame on a given VAP * @vap_dev: DP vdev handle @@ -1174,10 +1228,11 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf, */ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf) { - struct ether_header *eh; + struct ether_header *eh = NULL; struct dp_tx_msdu_info_s msdu_info; struct dp_tx_seg_info_s seg_info; struct dp_vdev *vdev = (struct dp_vdev *) vap_dev; + uint16_t peer_id = HTT_INVALID_PEER; qdf_mem_set(&msdu_info, sizeof(msdu_info), 0x0); qdf_mem_set(&seg_info, sizeof(seg_info), 0x0); @@ -1294,6 +1349,16 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf) } + if (vdev->nawds_enabled) { + eh = (struct ether_header *)qdf_nbuf_data(nbuf); + if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost)) { + nbuf = dp_tx_prepare_nawds(vdev, nbuf, msdu_info.tid, + &msdu_info.tx_queue, + msdu_info.meta_data, peer_id); + return nbuf; + } + } + /* Single linear frame */ /* * If nbuf is a simple linear frame, use send_single function to @@ -1301,7 +1366,7 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf) * SRNG. There is no need to setup a MSDU extension descriptor. */ nbuf = dp_tx_send_msdu_single(vdev, nbuf, msdu_info.tid, - &msdu_info.tx_queue, msdu_info.meta_data); + &msdu_info.tx_queue, msdu_info.meta_data, peer_id); return nbuf; diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 81493963bc..0386503709 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -104,6 +104,10 @@ union dp_rx_desc_list_elem_t; (_a)[4] == 0xff && \ (_a)[5] == 0xff) #define IS_LLC_PRESENT(typeorlen) ((typeorlen) >= 0x600) +#define DP_FRAME_FC0_TYPE_MASK 0x0c +#define DP_FRAME_FC0_TYPE_DATA 0x08 +#define DP_FRAME_IS_DATA(_frame) \ + (((_frame)->i_fc[0] & DP_FRAME_FC0_TYPE_MASK) == DP_FRAME_FC0_TYPE_DATA) /** * macros to convert hw mac id to sw mac id: @@ -968,4 +972,18 @@ struct dp_peer { TAILQ_HEAD(, dp_ast_entry) ast_entry_list; /* TBD */ }; + +#ifdef CONFIG_WIN +/* + * dp_invalid_peer_msg + * @nbuf: data buffer + * @wh: 802.11 header + * @vdev_id: id of vdev + */ +struct dp_invalid_peer_msg { + qdf_nbuf_t nbuf; + struct ieee80211_frame *wh; + uint8_t vdev_id; +}; +#endif #endif /* _DP_TYPES_H_ */