drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/mvm/time-sync.c
Extension
.c
Size
4897 bytes
Lines
174
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
 * Copyright (C) 2022, 2026 Intel Corporation
 */

#include "mvm.h"
#include "time-sync.h"
#include <linux/ieee80211.h>

void iwl_mvm_init_time_sync(struct iwl_time_sync_data *data)
{
	skb_queue_head_init(&data->frame_list);
}

static bool iwl_mvm_is_skb_match(struct sk_buff *skb, u8 *addr, u8 dialog_token)
{
	struct ieee80211_mgmt *mgmt = (void *)skb->data;
	u8 skb_dialog_token;

	if (ieee80211_is_timing_measurement(skb))
		skb_dialog_token = mgmt->u.action.wnm_timing_msr.dialog_token;
	else
		skb_dialog_token = mgmt->u.action.ftm.dialog_token;

	if ((ether_addr_equal(mgmt->sa, addr) ||
	     ether_addr_equal(mgmt->da, addr)) &&
	    skb_dialog_token == dialog_token)
		return true;

	return false;
}

static struct sk_buff *iwl_mvm_time_sync_find_skb(struct iwl_mvm *mvm, u8 *addr,
						  u8 dialog_token)
{
	struct sk_buff *skb;

	/* The queue is expected to have only one SKB. If there are other SKBs
	 * in the queue, they did not get a time sync notification and are
	 * probably obsolete by now, so drop them.
	 */
	while ((skb = skb_dequeue(&mvm->time_sync.frame_list))) {
		if (iwl_mvm_is_skb_match(skb, addr, dialog_token))
			break;

		kfree_skb(skb);
		skb = NULL;
	}

	return skb;
}

static u64 iwl_mvm_get_64_bit(__le32 high, __le32 low)
{
	return ((u64)le32_to_cpu(high) << 32) | le32_to_cpu(low);
}

void iwl_mvm_time_sync_msmt_event(struct iwl_mvm *mvm,
				  struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_time_msmt_notify *notif = (void *)pkt->data;
	struct ieee80211_rx_status *rx_status;
	struct skb_shared_hwtstamps *shwt;
	u64 ts_10ns;
	struct sk_buff *skb =
		iwl_mvm_time_sync_find_skb(mvm, notif->peer_addr,
					   le32_to_cpu(notif->dialog_token));
	u64 adj_time;

	if (!skb) {
		IWL_DEBUG_INFO(mvm, "Time sync event but no pending skb\n");
		return;
	}

	ts_10ns = iwl_mvm_get_64_bit(notif->t2_hi, notif->t2_lo);
	adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
	shwt = skb_hwtstamps(skb);
	shwt->hwtstamp = ktime_set(0, adj_time);

	ts_10ns = iwl_mvm_get_64_bit(notif->t3_hi, notif->t3_lo);
	adj_time = iwl_mvm_ptp_get_adj_time(mvm, ts_10ns * 10);
	rx_status = IEEE80211_SKB_RXCB(skb);
	rx_status->ack_tx_hwtstamp = ktime_set(0, adj_time);

	IWL_DEBUG_INFO(mvm,
		       "Time sync: RX event - report frame t2=%llu t3=%llu\n",
		       ktime_to_ns(shwt->hwtstamp),
		       ktime_to_ns(rx_status->ack_tx_hwtstamp));
	ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);

Annotation

Implementation Notes