Files
android_kernel_samsung_sm86…/dp/wifi3.0/be/mlo/dp_mlo.c
Chaithanya Garrepalli 362e95bae6 qcacmn: Add NULL check in dp_mlo_get_soc_ref_by_chip_id
In dp_mlo_get_soc_ref_by_chip_id API add null check
for ml_ctxt

Also correct intraBSS code for mlo disabled cases

Change-Id: I25eb07e9ccd714ba819730c765dc07b00dd15482
2022-01-15 03:03:16 -08:00

615 baris
16 KiB
C
Mentah Salahkan Riwayat

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <wlan_utility.h>
#include <dp_internal.h>
#include <dp_htt.h>
#include <hal_be_api.h>
#include "dp_mlo.h"
#include <dp_be.h>
#include <dp_htt.h>
#include <dp_internal.h>
#include <wlan_cfg.h>
#include <wlan_mlo_mgr_cmn.h>
/*
* dp_mlo_ctxt_attach_wifi3 () Attach DP MLO context
*
* Return: DP MLO context handle on success, NULL on failure
*/
struct cdp_mlo_ctxt *
dp_mlo_ctxt_attach_wifi3(struct cdp_ctrl_mlo_mgr *ctrl_ctxt)
{
struct dp_mlo_ctxt *mlo_ctxt =
qdf_mem_malloc(sizeof(struct dp_mlo_ctxt));
if (!mlo_ctxt) {
dp_err("Failed to allocate DP MLO Context");
return NULL;
}
mlo_ctxt->ctrl_ctxt = ctrl_ctxt;
if (dp_mlo_peer_find_hash_attach_be
(mlo_ctxt, DP_MAX_MLO_PEER) != QDF_STATUS_SUCCESS) {
dp_err("Failed to allocate peer hash");
qdf_mem_free(mlo_ctxt);
return NULL;
}
qdf_spinlock_create(&mlo_ctxt->ml_soc_list_lock);
return dp_mlo_ctx_to_cdp(mlo_ctxt);
}
qdf_export_symbol(dp_mlo_ctxt_attach_wifi3);
/*
* dp_mlo_ctxt_detach_wifi3 () Detach DP MLO context
*
* @ml_ctxt: pointer to DP MLO context
*
* Return: void
*/
void dp_mlo_ctxt_detach_wifi3(struct cdp_mlo_ctxt *cdp_ml_ctxt)
{
struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
if (!cdp_ml_ctxt)
return;
qdf_spinlock_destroy(&mlo_ctxt->ml_soc_list_lock);
dp_mlo_peer_find_hash_detach_be(mlo_ctxt);
qdf_mem_free(mlo_ctxt);
}
qdf_export_symbol(dp_mlo_ctxt_detach_wifi3);
/*
* dp_mlo_set_soc_by_chip_id() Add DP soc to ML context soc list
*
* @ml_ctxt: DP ML context handle
* @soc: DP soc handle
* @chip_id: MLO chip id
*
* Return: void
*/
void dp_mlo_set_soc_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
struct dp_soc *soc,
uint8_t chip_id)
{
qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
ml_ctxt->ml_soc_list[chip_id] = soc;
qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
}
/*
* dp_mlo_get_soc_ref_by_chip_id() Get DP soc from DP ML context.
* This API will increment a reference count for DP soc. Caller has
* to take care for decrementing refcount.
*
* @ml_ctxt: DP ML context handle
* @chip_id: MLO chip id
*
* Return: dp_soc
*/
struct dp_soc*
dp_mlo_get_soc_ref_by_chip_id(struct dp_mlo_ctxt *ml_ctxt,
uint8_t chip_id)
{
struct dp_soc *soc = NULL;
if (!ml_ctxt) {
dp_warn("MLO context not created, MLO not enabled");
return NULL;
}
qdf_spin_lock_bh(&ml_ctxt->ml_soc_list_lock);
soc = ml_ctxt->ml_soc_list[chip_id];
if (!soc) {
qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
return NULL;
}
qdf_atomic_inc(&soc->ref_count);
qdf_spin_unlock_bh(&ml_ctxt->ml_soc_list_lock);
return soc;
}
static QDF_STATUS dp_partner_soc_rx_hw_cc_init(struct dp_mlo_ctxt *mlo_ctxt,
struct dp_soc_be *be_soc)
{
uint8_t i;
struct dp_soc *partner_soc;
struct dp_soc_be *be_partner_soc;
uint8_t pool_id;
QDF_STATUS qdf_status;
for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
partner_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
if (!partner_soc)
continue;
be_partner_soc = dp_get_be_soc_from_dp_soc(partner_soc);
for (pool_id = 0; pool_id < MAX_RXDESC_POOLS; pool_id++) {
qdf_status =
dp_hw_cookie_conversion_init
(be_soc,
&be_partner_soc->rx_cc_ctx[pool_id]);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
dp_alert("MLO partner soc RX CC init failed");
return qdf_status;
}
}
}
return qdf_status;
}
static void dp_mlo_soc_setup(struct cdp_soc_t *soc_hdl,
struct cdp_mlo_ctxt *cdp_ml_ctxt)
{
struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
if (!cdp_ml_ctxt)
return;
dp_mlo_set_soc_by_chip_id(mlo_ctxt, soc, be_soc->mlo_chip_id);
}
static void dp_mlo_soc_teardown(struct cdp_soc_t *soc_hdl,
struct cdp_mlo_ctxt *cdp_ml_ctxt)
{
struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
if (!cdp_ml_ctxt)
return;
dp_mlo_set_soc_by_chip_id(mlo_ctxt, NULL, be_soc->mlo_chip_id);
}
static QDF_STATUS dp_mlo_add_ptnr_vdev(struct dp_vdev *vdev1,
struct dp_vdev *vdev2,
struct dp_soc *soc, uint8_t pdev_id)
{
struct dp_soc_be *soc_be = dp_get_be_soc_from_dp_soc(soc);
struct dp_vdev_be *vdev2_be = dp_get_be_vdev_from_dp_vdev(vdev2);
/* return when valid entry exists */
if (vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] !=
CDP_INVALID_VDEV_ID)
return QDF_STATUS_SUCCESS;
if (dp_vdev_get_ref(soc, vdev1, DP_MOD_ID_RX) !=
QDF_STATUS_SUCCESS) {
qdf_info("%pK: unable to get vdev reference vdev %pK vdev_id %u",
soc, vdev1, vdev1->vdev_id);
return QDF_STATUS_E_FAILURE;
}
vdev2_be->partner_vdev_list[soc_be->mlo_chip_id][pdev_id] =
vdev1->vdev_id;
mlo_debug("Add vdev%d to vdev%d list, mlo_chip_id = %d pdev_id = %d\n",
vdev1->vdev_id, vdev2->vdev_id, soc_be->mlo_chip_id, pdev_id);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS dp_update_mlo_ptnr_list(struct cdp_soc_t *soc_hdl,
int8_t partner_vdev_ids[], uint8_t num_vdevs,
uint8_t self_vdev_id)
{
int i, j;
struct dp_soc *self_soc = cdp_soc_t_to_dp_soc(soc_hdl);
struct dp_vdev *self_vdev;
QDF_STATUS ret = QDF_STATUS_SUCCESS;
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(self_soc);
struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
if (!dp_mlo)
return QDF_STATUS_E_FAILURE;
self_vdev = dp_vdev_get_ref_by_id(self_soc, self_vdev_id, DP_MOD_ID_RX);
if (!self_vdev)
return QDF_STATUS_E_FAILURE;
/* go through the input vdev id list and if there are partner vdevs,
* - then add the current vdev's id to partner vdev's list using pdev_id and
* increase the reference
* - add partner vdev to self list and increase the reference
*/
for (i = 0; i < num_vdevs; i++) {
if (partner_vdev_ids[i] == CDP_INVALID_VDEV_ID)
continue;
for (j = 0; j < WLAN_MAX_MLO_CHIPS; j++) {
struct dp_soc *soc =
dp_mlo_get_soc_ref_by_chip_id(dp_mlo, j);
if (soc) {
struct dp_vdev *vdev;
vdev = dp_vdev_get_ref_by_id(soc,
partner_vdev_ids[i], DP_MOD_ID_RX);
if (vdev) {
if (vdev == self_vdev) {
dp_vdev_unref_delete(soc,
vdev, DP_MOD_ID_RX);
/*dp_soc_unref_delete(soc); */
continue;
}
if (qdf_is_macaddr_equal(
(struct qdf_mac_addr *)self_vdev->mld_mac_addr.raw,
(struct qdf_mac_addr *)vdev->mld_mac_addr.raw)) {
if (dp_mlo_add_ptnr_vdev(self_vdev,
vdev, self_soc,
self_vdev->pdev->pdev_id) !=
QDF_STATUS_SUCCESS) {
dp_err("Unable to add self to partner vdev's list");
dp_vdev_unref_delete(soc,
vdev, DP_MOD_ID_RX);
/* TODO - release soc ref here */
/* dp_soc_unref_delete(soc);*/
ret = QDF_STATUS_E_FAILURE;
goto exit;
}
/* add to self list */
if (dp_mlo_add_ptnr_vdev(vdev, self_vdev, soc,
vdev->pdev->pdev_id) !=
QDF_STATUS_SUCCESS) {
dp_err("Unable to add vdev to self vdev's list");
dp_vdev_unref_delete(self_soc,
vdev, DP_MOD_ID_RX);
/* TODO - relase soc ref here */
/* dp_soc_unref_delete(soc);*/
ret = QDF_STATUS_E_FAILURE;
goto exit;
}
}
dp_vdev_unref_delete(soc, vdev,
DP_MOD_ID_RX);
} /* vdev */
/* TODO - release soc ref here */
/* dp_soc_unref_delete(soc); */
} /* soc */
} /* for */
} /* for */
exit:
dp_vdev_unref_delete(self_soc, self_vdev, DP_MOD_ID_RX);
return ret;
}
void dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
struct dp_vdev_be *vdev_be = dp_get_be_vdev_from_dp_vdev(vdev);
struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
uint8_t soc_id = be_soc->mlo_chip_id;
uint8_t pdev_id = vdev->pdev->pdev_id;
int i, j;
for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
for (j = 0; j < WLAN_MAX_MLO_LINKS_PER_SOC; j++) {
struct dp_vdev *pr_vdev;
struct dp_soc *pr_soc;
struct dp_soc_be *pr_soc_be;
struct dp_pdev *pr_pdev;
struct dp_vdev_be *pr_vdev_be;
if (vdev_be->partner_vdev_list[i][j] ==
CDP_INVALID_VDEV_ID)
continue;
pr_soc = dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
pr_soc_be = dp_get_be_soc_from_dp_soc(pr_soc);
pr_vdev = dp_vdev_get_ref_by_id(pr_soc,
vdev_be->partner_vdev_list[i][j],
DP_MOD_ID_RX);
if (!pr_vdev)
continue;
/* release ref and remove self vdev from partner list */
pr_vdev_be = dp_get_be_vdev_from_dp_vdev(pr_vdev);
dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX);
pr_vdev_be->partner_vdev_list[soc_id][pdev_id] =
CDP_INVALID_VDEV_ID;
/* release ref and remove partner vdev from self list */
dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX);
pr_pdev = pr_vdev->pdev;
vdev_be->partner_vdev_list[pr_soc_be->mlo_chip_id][pr_pdev->pdev_id] =
CDP_INVALID_VDEV_ID;
dp_vdev_unref_delete(pr_soc, pr_vdev, DP_MOD_ID_RX);
}
}
}
static void dp_mlo_setup_complete(struct cdp_mlo_ctxt *cdp_ml_ctxt)
{
struct dp_mlo_ctxt *mlo_ctxt = cdp_mlo_ctx_to_dp(cdp_ml_ctxt);
int i;
struct dp_soc *soc;
struct dp_soc_be *be_soc;
QDF_STATUS qdf_status;
if (!cdp_ml_ctxt)
return;
for (i = 0; i < WLAN_MAX_MLO_CHIPS; i++) {
soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, i);
if (!soc)
continue;
be_soc = dp_get_be_soc_from_dp_soc(soc);
qdf_status = dp_partner_soc_rx_hw_cc_init(mlo_ctxt, be_soc);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
dp_alert("MLO partner SOC Rx desc CC init failed");
qdf_assert_always(0);
}
}
}
static struct cdp_mlo_ops dp_mlo_ops = {
.mlo_soc_setup = dp_mlo_soc_setup,
.mlo_soc_teardown = dp_mlo_soc_teardown,
.update_mlo_ptnr_list = dp_update_mlo_ptnr_list,
.mlo_setup_complete = dp_mlo_setup_complete,
};
void dp_soc_mlo_fill_params(struct dp_soc *soc,
struct cdp_soc_attach_params *params)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
if (!params->mlo_enabled) {
dp_warn("MLO not enabled on SOC");
return;
}
be_soc->mlo_chip_id = params->mlo_chip_id;
be_soc->ml_ctxt = cdp_mlo_ctx_to_dp(params->ml_context);
be_soc->mlo_enabled = 1;
soc->cdp_soc.ops->mlo_ops = &dp_mlo_ops;
}
void dp_pdev_mlo_fill_params(struct dp_pdev *pdev,
struct cdp_pdev_attach_params *params)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(pdev->soc);
struct dp_pdev_be *be_pdev = dp_get_be_pdev_from_dp_pdev(pdev);
if (!be_soc->mlo_enabled) {
dp_info("MLO not enabled on SOC");
return;
}
be_pdev->mlo_link_id = params->mlo_link_id;
}
void dp_mlo_partner_chips_map(struct dp_soc *soc,
struct dp_peer *peer,
uint16_t peer_id)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
bool is_ml_peer_id =
HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
uint8_t chip_id;
struct dp_soc *temp_soc;
if (!mlo_ctxt)
return;
/* for non ML peer dont map on partner chips*/
if (!is_ml_peer_id)
return;
qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
temp_soc = mlo_ctxt->ml_soc_list[chip_id];
if (!temp_soc)
continue;
/* skip if this is current soc */
if (temp_soc == soc)
continue;
dp_peer_find_id_to_obj_add(temp_soc, peer, peer_id);
}
qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
}
qdf_export_symbol(dp_mlo_partner_chips_map);
void dp_mlo_partner_chips_unmap(struct dp_soc *soc,
uint16_t peer_id)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
bool is_ml_peer_id =
HTT_RX_PEER_META_DATA_V1_ML_PEER_VALID_GET(peer_id);
uint8_t chip_id;
struct dp_soc *temp_soc;
if (!is_ml_peer_id)
return;
if (!mlo_ctxt)
return;
qdf_spin_lock_bh(&mlo_ctxt->ml_soc_list_lock);
for (chip_id = 0; chip_id < DP_MAX_MLO_CHIPS; chip_id++) {
temp_soc = mlo_ctxt->ml_soc_list[chip_id];
if (!temp_soc)
continue;
/* skip if this is current soc */
if (temp_soc == soc)
continue;
dp_peer_find_id_to_obj_remove(temp_soc, peer_id);
}
qdf_spin_unlock_bh(&mlo_ctxt->ml_soc_list_lock);
}
qdf_export_symbol(dp_mlo_partner_chips_unmap);
uint8_t dp_mlo_get_chip_id(struct dp_soc *soc)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
return be_soc->mlo_chip_id;
}
qdf_export_symbol(dp_mlo_get_chip_id);
struct dp_peer *
dp_link_peer_hash_find_by_chip_id(struct dp_soc *soc,
uint8_t *peer_mac_addr,
int mac_addr_is_aligned,
uint8_t vdev_id,
uint8_t chip_id,
enum dp_mod_id mod_id)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
struct dp_soc *link_peer_soc = NULL;
struct dp_peer *peer = NULL;
if (!mlo_ctxt)
return NULL;
link_peer_soc = dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
if (!link_peer_soc)
return NULL;
peer = dp_peer_find_hash_find(link_peer_soc, peer_mac_addr,
mac_addr_is_aligned, vdev_id,
mod_id);
qdf_atomic_dec(&link_peer_soc->ref_count);
return peer;
}
qdf_export_symbol(dp_link_peer_hash_find_by_chip_id);
struct dp_soc *
dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t reo_ring_num)
{
struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc);
struct dp_mlo_ctxt *mlo_ctxt = be_soc->ml_ctxt;
uint8_t chip_id;
uint8_t rx_ring_mask;
if (!be_soc->mlo_enabled || !mlo_ctxt)
return soc;
for (chip_id = 0; chip_id < WLAN_MAX_MLO_CHIPS; chip_id++) {
rx_ring_mask =
wlan_cfg_mlo_rx_ring_map_get_by_chip_id
(soc->wlan_cfg_ctx, chip_id);
if (rx_ring_mask & (1 << reo_ring_num))
return dp_mlo_get_soc_ref_by_chip_id(mlo_ctxt, chip_id);
}
return soc;
}
#ifdef WLAN_MCAST_MLO
void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc,
struct dp_vdev_be *be_vdev,
dp_ptnr_vdev_iter_func func,
void *arg,
enum dp_mod_id mod_id)
{
int i = 0;
int j = 0;
struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
struct dp_soc *ptnr_soc =
dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
if (!ptnr_soc)
continue;
for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
struct dp_vdev *ptnr_vdev;
ptnr_vdev = dp_vdev_get_ref_by_id(
ptnr_soc,
be_vdev->partner_vdev_list[i][j],
mod_id);
if (!ptnr_vdev)
continue;
(*func)(be_vdev, ptnr_vdev, arg);
dp_vdev_unref_delete(ptnr_vdev->pdev->soc,
ptnr_vdev,
mod_id);
}
}
}
qdf_export_symbol(dp_mcast_mlo_iter_ptnr_vdev);
struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc,
struct dp_vdev_be *be_vdev,
enum dp_mod_id mod_id)
{
int i = 0;
int j = 0;
struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt;
for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) {
struct dp_soc *ptnr_soc =
dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i);
if (!ptnr_soc)
continue;
for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) {
struct dp_vdev *ptnr_vdev = NULL;
struct dp_vdev_be *be_ptnr_vdev = NULL;
ptnr_vdev = dp_vdev_get_ref_by_id(
ptnr_soc,
be_vdev->partner_vdev_list[i][j],
mod_id);
if (!ptnr_vdev)
continue;
be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev);
if (be_ptnr_vdev->mcast_primary)
return ptnr_vdev;
dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc,
&be_ptnr_vdev->vdev,
mod_id);
}
}
return NULL;
}
qdf_export_symbol(dp_mlo_get_mcast_primary_vdev);
#endif