Path: blob/main/sys/contrib/dev/athk/ath12k/peer.c
48375 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.4*/56#include "core.h"7#include "peer.h"8#include "debug.h"910struct ath12k_peer *ath12k_peer_find(struct ath12k_base *ab, int vdev_id,11const u8 *addr)12{13struct ath12k_peer *peer;1415lockdep_assert_held(&ab->base_lock);1617list_for_each_entry(peer, &ab->peers, list) {18if (peer->vdev_id != vdev_id)19continue;20if (!ether_addr_equal(peer->addr, addr))21continue;2223return peer;24}2526return NULL;27}2829static struct ath12k_peer *ath12k_peer_find_by_pdev_idx(struct ath12k_base *ab,30u8 pdev_idx, const u8 *addr)31{32struct ath12k_peer *peer;3334lockdep_assert_held(&ab->base_lock);3536list_for_each_entry(peer, &ab->peers, list) {37if (peer->pdev_idx != pdev_idx)38continue;39if (!ether_addr_equal(peer->addr, addr))40continue;4142return peer;43}4445return NULL;46}4748struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab,49const u8 *addr)50{51struct ath12k_peer *peer;5253lockdep_assert_held(&ab->base_lock);5455list_for_each_entry(peer, &ab->peers, list) {56if (!ether_addr_equal(peer->addr, addr))57continue;5859return peer;60}6162return NULL;63}6465struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab,66int peer_id)67{68struct ath12k_peer *peer;6970lockdep_assert_held(&ab->base_lock);7172list_for_each_entry(peer, &ab->peers, list)73if (peer_id == peer->peer_id)74return peer;7576return NULL;77}7879bool ath12k_peer_exist_by_vdev_id(struct ath12k_base *ab, int vdev_id)80{81struct ath12k_peer *peer;8283spin_lock_bh(&ab->base_lock);8485list_for_each_entry(peer, &ab->peers, list) {86if (vdev_id == peer->vdev_id) {87spin_unlock_bh(&ab->base_lock);88return true;89}90}91spin_unlock_bh(&ab->base_lock);92return false;93}9495struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab,96int ast_hash)97{98struct ath12k_peer *peer;99100lockdep_assert_held(&ab->base_lock);101102list_for_each_entry(peer, &ab->peers, list)103if (ast_hash == peer->ast_hash)104return peer;105106return NULL;107}108109void ath12k_peer_unmap_event(struct ath12k_base *ab, u16 peer_id)110{111struct ath12k_peer *peer;112113spin_lock_bh(&ab->base_lock);114115peer = ath12k_peer_find_by_id(ab, peer_id);116if (!peer) {117ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n",118peer_id);119goto exit;120}121122ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",123peer->vdev_id, peer->addr, peer_id);124125list_del(&peer->list);126kfree(peer);127wake_up(&ab->peer_mapping_wq);128129exit:130spin_unlock_bh(&ab->base_lock);131}132133void ath12k_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,134u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)135{136struct ath12k_peer *peer;137138spin_lock_bh(&ab->base_lock);139peer = ath12k_peer_find(ab, vdev_id, mac_addr);140if (!peer) {141peer = kzalloc(sizeof(*peer), GFP_ATOMIC);142if (!peer)143goto exit;144145peer->vdev_id = vdev_id;146peer->peer_id = peer_id;147peer->ast_hash = ast_hash;148peer->hw_peer_id = hw_peer_id;149ether_addr_copy(peer->addr, mac_addr);150list_add(&peer->list, &ab->peers);151wake_up(&ab->peer_mapping_wq);152}153154ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",155vdev_id, mac_addr, peer_id);156157exit:158spin_unlock_bh(&ab->base_lock);159}160161static int ath12k_wait_for_peer_common(struct ath12k_base *ab, int vdev_id,162const u8 *addr, bool expect_mapped)163{164int ret;165166ret = wait_event_timeout(ab->peer_mapping_wq, ({167bool mapped;168169spin_lock_bh(&ab->base_lock);170mapped = !!ath12k_peer_find(ab, vdev_id, addr);171spin_unlock_bh(&ab->base_lock);172173(mapped == expect_mapped ||174test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags));175}), 3 * HZ);176177if (ret <= 0)178return -ETIMEDOUT;179180return 0;181}182183void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id)184{185struct ath12k_peer *peer, *tmp;186struct ath12k_base *ab = ar->ab;187188lockdep_assert_held(&ar->conf_mutex);189190spin_lock_bh(&ab->base_lock);191list_for_each_entry_safe(peer, tmp, &ab->peers, list) {192if (peer->vdev_id != vdev_id)193continue;194195ath12k_warn(ab, "removing stale peer %pM from vdev_id %d\n",196peer->addr, vdev_id);197198list_del(&peer->list);199kfree(peer);200ar->num_peers--;201}202203spin_unlock_bh(&ab->base_lock);204}205206static int ath12k_wait_for_peer_deleted(struct ath12k *ar, int vdev_id, const u8 *addr)207{208return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, false);209}210211int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,212const u8 *addr)213{214int ret;215unsigned long time_left;216217ret = ath12k_wait_for_peer_deleted(ar, vdev_id, addr);218if (ret) {219ath12k_warn(ar->ab, "failed wait for peer deleted");220return ret;221}222223time_left = wait_for_completion_timeout(&ar->peer_delete_done,2243 * HZ);225if (time_left == 0) {226ath12k_warn(ar->ab, "Timeout in receiving peer delete response\n");227return -ETIMEDOUT;228}229230return 0;231}232233int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)234{235int ret;236237lockdep_assert_held(&ar->conf_mutex);238239reinit_completion(&ar->peer_delete_done);240241ret = ath12k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);242if (ret) {243ath12k_warn(ar->ab,244"failed to delete peer vdev_id %d addr %pM ret %d\n",245vdev_id, addr, ret);246return ret;247}248249ret = ath12k_wait_for_peer_delete_done(ar, vdev_id, addr);250if (ret)251return ret;252253ar->num_peers--;254255return 0;256}257258static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8 *addr)259{260return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true);261}262263int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,264struct ieee80211_sta *sta,265struct ath12k_wmi_peer_create_arg *arg)266{267struct ath12k_peer *peer;268int ret;269270lockdep_assert_held(&ar->conf_mutex);271272if (ar->num_peers > (ar->max_num_peers - 1)) {273ath12k_warn(ar->ab,274"failed to create peer due to insufficient peer entry resource in firmware\n");275return -ENOBUFS;276}277278spin_lock_bh(&ar->ab->base_lock);279peer = ath12k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, arg->peer_addr);280if (peer) {281spin_unlock_bh(&ar->ab->base_lock);282return -EINVAL;283}284spin_unlock_bh(&ar->ab->base_lock);285286ret = ath12k_wmi_send_peer_create_cmd(ar, arg);287if (ret) {288ath12k_warn(ar->ab,289"failed to send peer create vdev_id %d ret %d\n",290arg->vdev_id, ret);291return ret;292}293294ret = ath12k_wait_for_peer_created(ar, arg->vdev_id,295arg->peer_addr);296if (ret)297return ret;298299spin_lock_bh(&ar->ab->base_lock);300301peer = ath12k_peer_find(ar->ab, arg->vdev_id, arg->peer_addr);302if (!peer) {303spin_unlock_bh(&ar->ab->base_lock);304ath12k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",305arg->peer_addr, arg->vdev_id);306307reinit_completion(&ar->peer_delete_done);308309ret = ath12k_wmi_send_peer_delete_cmd(ar, arg->peer_addr,310arg->vdev_id);311if (ret) {312ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",313arg->vdev_id, arg->peer_addr);314return ret;315}316317ret = ath12k_wait_for_peer_delete_done(ar, arg->vdev_id,318arg->peer_addr);319if (ret)320return ret;321322return -ENOENT;323}324325peer->pdev_idx = ar->pdev_idx;326peer->sta = sta;327328if (arvif->vif->type == NL80211_IFTYPE_STATION) {329arvif->ast_hash = peer->ast_hash;330arvif->ast_idx = peer->hw_peer_id;331}332333peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;334peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;335336ar->num_peers++;337338spin_unlock_bh(&ar->ab->base_lock);339340return 0;341}342343344