mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-07 05:45:24 +00:00

This change reflects the correct ownership of aux_sta, as it is not a property of the link but rather of the virtual interface. Updated the initialization, cleanup and access logic for the aux_sta member to align with its new location within iwl_mld_vif. Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com> Reviewed-by: Somashekhar Puttagangaiah <somashekhar.puttagangaiah@intel.com> Link: https://patch.msgid.link/20250509104454.2582160-12-miriam.rachel.korenblit@intel.com Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
274 lines
8.7 KiB
C
274 lines
8.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
|
/*
|
|
* Copyright (C) 2024-2025 Intel Corporation
|
|
*/
|
|
|
|
#ifndef __iwl_mld_sta_h__
|
|
#define __iwl_mld_sta_h__
|
|
|
|
#include <net/mac80211.h>
|
|
|
|
#include "mld.h"
|
|
#include "tx.h"
|
|
|
|
/**
|
|
* struct iwl_mld_rxq_dup_data - Duplication detection data, per STA & Rx queue
|
|
* @last_seq: last sequence per tid.
|
|
* @last_sub_frame_idx: the index of the last subframe in an A-MSDU. This value
|
|
* will be zero if the packet is not part of an A-MSDU.
|
|
*/
|
|
struct iwl_mld_rxq_dup_data {
|
|
__le16 last_seq[IWL_MAX_TID_COUNT + 1];
|
|
u8 last_sub_frame_idx[IWL_MAX_TID_COUNT + 1];
|
|
} ____cacheline_aligned_in_smp;
|
|
|
|
/**
|
|
* struct iwl_mld_link_sta - link-level station
|
|
*
|
|
* This represents the link-level sta - the driver level equivalent to the
|
|
* ieee80211_link_sta
|
|
*
|
|
* @last_rate_n_flags: rate_n_flags from the last &iwl_tlc_update_notif
|
|
* @signal_avg: the signal average coming from the firmware
|
|
* @in_fw: whether the link STA is uploaded to the FW (false during restart)
|
|
* @rcu_head: RCU head for freeing this object
|
|
* @fw_id: the FW id of this link sta.
|
|
*/
|
|
struct iwl_mld_link_sta {
|
|
/* Add here fields that need clean up on restart */
|
|
struct_group(zeroed_on_hw_restart,
|
|
u32 last_rate_n_flags;
|
|
bool in_fw;
|
|
s8 signal_avg;
|
|
);
|
|
/* And here fields that survive a fw restart */
|
|
struct rcu_head rcu_head;
|
|
u32 fw_id;
|
|
};
|
|
|
|
#define iwl_mld_link_sta_dereference_check(mld_sta, link_id) \
|
|
rcu_dereference_check((mld_sta)->link[link_id], \
|
|
lockdep_is_held(&mld_sta->mld->wiphy->mtx))
|
|
|
|
#define for_each_mld_link_sta(mld_sta, link_sta, link_id) \
|
|
for (link_id = 0; link_id < ARRAY_SIZE((mld_sta)->link); \
|
|
link_id++) \
|
|
if ((link_sta = \
|
|
iwl_mld_link_sta_dereference_check(mld_sta, link_id)))
|
|
|
|
#define IWL_NUM_DEFAULT_KEYS 4
|
|
|
|
/* struct iwl_mld_ptk_pn - Holds Packet Number (PN) per TID.
|
|
* @rcu_head: RCU head for freeing this data.
|
|
* @pn: Array storing PN for each TID.
|
|
*/
|
|
struct iwl_mld_ptk_pn {
|
|
struct rcu_head rcu_head;
|
|
struct {
|
|
u8 pn[IWL_MAX_TID_COUNT][IEEE80211_CCMP_PN_LEN];
|
|
} ____cacheline_aligned_in_smp q[];
|
|
};
|
|
|
|
/**
|
|
* struct iwl_mld_per_link_mpdu_counter - per-link TX/RX MPDU counters
|
|
*
|
|
* @tx: Number of TX MPDUs.
|
|
* @rx: Number of RX MPDUs.
|
|
*/
|
|
struct iwl_mld_per_link_mpdu_counter {
|
|
u32 tx;
|
|
u32 rx;
|
|
};
|
|
|
|
/**
|
|
* struct iwl_mld_per_q_mpdu_counter - per-queue MPDU counter
|
|
*
|
|
* @lock: Needed to protect the counters when modified from statistics.
|
|
* @per_link: per-link counters.
|
|
* @window_start_time: timestamp of the counting-window start
|
|
*/
|
|
struct iwl_mld_per_q_mpdu_counter {
|
|
spinlock_t lock;
|
|
struct iwl_mld_per_link_mpdu_counter per_link[IWL_FW_MAX_LINK_ID + 1];
|
|
unsigned long window_start_time;
|
|
} ____cacheline_aligned_in_smp;
|
|
|
|
/**
|
|
* struct iwl_mld_sta - representation of a station in the driver.
|
|
*
|
|
* This represent the MLD-level sta, and will not be added to the FW.
|
|
* Embedded in ieee80211_sta.
|
|
*
|
|
* @vif: pointer the vif object.
|
|
* @sta_state: station state according to enum %ieee80211_sta_state
|
|
* @sta_type: type of this station. See &enum iwl_fw_sta_type
|
|
* @mld: a pointer to the iwl_mld object
|
|
* @dup_data: per queue duplicate packet detection data
|
|
* @data_tx_ant: stores the last TX antenna index; used for setting
|
|
* TX rate_n_flags for injected data frames (toggles on every TX failure).
|
|
* @tid_to_baid: a simple map of TID to Block-Ack fw id
|
|
* @deflink: This holds the default link STA information, for non MLO STA all
|
|
* link specific STA information is accessed through @deflink or through
|
|
* link[0] which points to address of @deflink. For MLO Link STA
|
|
* the first added link STA will point to deflink.
|
|
* @link: reference to Link Sta entries. For Non MLO STA, except 1st link,
|
|
* i.e link[0] all links would be assigned to NULL by default and
|
|
* would access link information via @deflink or link[0]. For MLO
|
|
* STA, first link STA being added will point its link pointer to
|
|
* @deflink address and remaining would be allocated and the address
|
|
* would be assigned to link[link_id] where link_id is the id assigned
|
|
* by the AP.
|
|
* @ptk_pn: Array of pointers to PTK PN data, used to track the Packet Number
|
|
* per key index and per queue (TID).
|
|
* @mpdu_counters: RX/TX MPDUs counters for each queue.
|
|
*/
|
|
struct iwl_mld_sta {
|
|
/* Add here fields that need clean up on restart */
|
|
struct_group(zeroed_on_hw_restart,
|
|
enum ieee80211_sta_state sta_state;
|
|
enum iwl_fw_sta_type sta_type;
|
|
);
|
|
/* And here fields that survive a fw restart */
|
|
struct iwl_mld *mld;
|
|
struct ieee80211_vif *vif;
|
|
struct iwl_mld_rxq_dup_data *dup_data;
|
|
u8 tid_to_baid[IWL_MAX_TID_COUNT];
|
|
u8 data_tx_ant;
|
|
|
|
struct iwl_mld_link_sta deflink;
|
|
struct iwl_mld_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
|
|
struct iwl_mld_ptk_pn __rcu *ptk_pn[IWL_NUM_DEFAULT_KEYS];
|
|
struct iwl_mld_per_q_mpdu_counter *mpdu_counters;
|
|
};
|
|
|
|
static inline struct iwl_mld_sta *
|
|
iwl_mld_sta_from_mac80211(struct ieee80211_sta *sta)
|
|
{
|
|
return (void *)sta->drv_priv;
|
|
}
|
|
|
|
static inline void
|
|
iwl_mld_cleanup_sta(void *data, struct ieee80211_sta *sta)
|
|
{
|
|
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
|
struct iwl_mld_link_sta *mld_link_sta;
|
|
u8 link_id;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(sta->txq); i++)
|
|
CLEANUP_STRUCT(iwl_mld_txq_from_mac80211(sta->txq[i]));
|
|
|
|
for_each_mld_link_sta(mld_sta, mld_link_sta, link_id) {
|
|
CLEANUP_STRUCT(mld_link_sta);
|
|
|
|
if (!ieee80211_vif_is_mld(mld_sta->vif)) {
|
|
/* not an MLD STA; only has the deflink with ID zero */
|
|
WARN_ON(link_id);
|
|
continue;
|
|
}
|
|
|
|
if (mld_sta->vif->active_links & BIT(link_id))
|
|
continue;
|
|
|
|
/* Should not happen as link removal should always succeed */
|
|
WARN_ON(1);
|
|
RCU_INIT_POINTER(mld_sta->link[link_id], NULL);
|
|
RCU_INIT_POINTER(mld_sta->mld->fw_id_to_link_sta[mld_link_sta->fw_id],
|
|
NULL);
|
|
if (mld_link_sta != &mld_sta->deflink)
|
|
kfree_rcu(mld_link_sta, rcu_head);
|
|
}
|
|
|
|
CLEANUP_STRUCT(mld_sta);
|
|
}
|
|
|
|
static inline struct iwl_mld_link_sta *
|
|
iwl_mld_link_sta_from_mac80211(struct ieee80211_link_sta *link_sta)
|
|
{
|
|
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
|
|
|
return iwl_mld_link_sta_dereference_check(mld_sta, link_sta->link_id);
|
|
}
|
|
|
|
int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
|
struct ieee80211_vif *vif, enum iwl_fw_sta_type type);
|
|
void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta);
|
|
int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld,
|
|
struct ieee80211_link_sta *link_sta);
|
|
u32 iwl_mld_fw_sta_id_mask(struct iwl_mld *mld, struct ieee80211_sta *sta);
|
|
int iwl_mld_update_all_link_stations(struct iwl_mld *mld,
|
|
struct ieee80211_sta *sta);
|
|
void iwl_mld_flush_sta_txqs(struct iwl_mld *mld, struct ieee80211_sta *sta);
|
|
void iwl_mld_wait_sta_txqs_empty(struct iwl_mld *mld,
|
|
struct ieee80211_sta *sta);
|
|
void iwl_mld_count_mpdu_rx(struct ieee80211_link_sta *link_sta, int queue,
|
|
u32 count);
|
|
void iwl_mld_count_mpdu_tx(struct ieee80211_link_sta *link_sta, u32 count);
|
|
|
|
/**
|
|
* struct iwl_mld_int_sta - representation of an internal station
|
|
* (a station that exist in FW and in driver, but not in mac80211)
|
|
*
|
|
* @sta_id: the index of the station in the fw
|
|
* @queue_id: the if of the queue used by the station
|
|
* @sta_type: station type. One of &iwl_fw_sta_type
|
|
*/
|
|
struct iwl_mld_int_sta {
|
|
u8 sta_id;
|
|
u32 queue_id;
|
|
enum iwl_fw_sta_type sta_type;
|
|
};
|
|
|
|
static inline void
|
|
iwl_mld_init_internal_sta(struct iwl_mld_int_sta *internal_sta)
|
|
{
|
|
internal_sta->sta_id = IWL_INVALID_STA;
|
|
internal_sta->queue_id = IWL_MLD_INVALID_QUEUE;
|
|
}
|
|
|
|
static inline void
|
|
iwl_mld_free_internal_sta(struct iwl_mld *mld,
|
|
struct iwl_mld_int_sta *internal_sta)
|
|
{
|
|
if (WARN_ON(internal_sta->sta_id == IWL_INVALID_STA))
|
|
return;
|
|
|
|
RCU_INIT_POINTER(mld->fw_id_to_link_sta[internal_sta->sta_id], NULL);
|
|
iwl_mld_init_internal_sta(internal_sta);
|
|
}
|
|
|
|
int iwl_mld_add_bcast_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
int iwl_mld_add_mcast_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
int iwl_mld_add_aux_sta(struct iwl_mld *mld,
|
|
struct iwl_mld_int_sta *internal_sta);
|
|
|
|
int iwl_mld_add_mon_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
void iwl_mld_remove_bcast_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
void iwl_mld_remove_mcast_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
void iwl_mld_remove_aux_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif);
|
|
|
|
void iwl_mld_remove_mon_sta(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_bss_conf *link);
|
|
|
|
int iwl_mld_update_link_stas(struct iwl_mld *mld,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_sta *sta,
|
|
u16 old_links, u16 new_links);
|
|
#endif /* __iwl_mld_sta_h__ */
|