// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <net/mac80211.h>
#include "iwl-io.h"
#include "iwl-prph.h"
#include "fw-api.h"
#include "mvm.h"
#include "time-event.h"
const u8 iwl_mvm_ac_to_tx_fifo[] = {
IWL_MVM_TX_FIFO_VO,
IWL_MVM_TX_FIFO_VI,
IWL_MVM_TX_FIFO_BE,
IWL_MVM_TX_FIFO_BK,
};
const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = {
IWL_GEN2_EDCA_TX_FIFO_VO,
IWL_GEN2_EDCA_TX_FIFO_VI,
IWL_GEN2_EDCA_TX_FIFO_BE,
IWL_GEN2_EDCA_TX_FIFO_BK,
IWL_GEN2_TRIG_TX_FIFO_VO,
IWL_GEN2_TRIG_TX_FIFO_VI,
IWL_GEN2_TRIG_TX_FIFO_BE,
IWL_GEN2_TRIG_TX_FIFO_BK,
};
struct iwl_mvm_mac_iface_iterator_data {
struct iwl_mvm *mvm;
struct ieee80211_vif *vif;
unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
enum iwl_tsf_id preferred_tsf;
bool found_vif;
};
static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_mac_iface_iterator_data *data = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u16 min_bi;
/* Skip the interface for which we are trying to assign a tsf_id */
if (vif == data->vif)
return;
/*
* The TSF is a hardware/firmware resource, there are 4 and
* the driver should assign and free them as needed. However,
* there are cases where 2 MACs should share the same TSF ID
* for the purpose of clock sync, an optimization to avoid
* clock drift causing overlapping TBTTs/DTIMs for a GO and
* client in the system.
*
* The firmware will decide according to the MAC type which
* will be the leader and follower. Clients that need to sync
* with a remote station will be the leader, and an AP or GO
* will be the follower.
*
* Depending on the new interface type it can be following
* or become the leader of an existing interface.
*/
switch (data->vif->type) {
case NL80211_IFTYPE_STATION:
/*
* The new interface is a client, so if the one we're iterating
* is an AP, and the beacon interval of the AP is a multiple or
* divisor of the beacon interval of the client, the same TSF
* should be used to avoid drift between the new client and
* existing AP. The existing AP will get drift updates from the
* new client context in this case.
*/
if (vif->type != NL80211_IFTYPE_AP ||
data->preferred_tsf != NUM_TSF_IDS ||
!test_bit(mvmvif->tsf_id, data->available_tsf_ids))
break;
min_bi = min(data->vif->bss_conf.beacon_int,
vif->bss_conf.beacon_int);
if (!min_bi)
break;
if ((data->vif->bss_conf.beacon_int -
vif->
|