1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2022 Intel Corporation
8 #include <linux/ieee80211.h>
10 void iwl_mvm_init_time_sync(struct iwl_time_sync_data
*data
)
12 skb_queue_head_init(&data
->frame_list
);
15 static bool iwl_mvm_is_skb_match(struct sk_buff
*skb
, u8
*addr
, u8 dialog_token
)
17 struct ieee80211_mgmt
*mgmt
= (void *)skb
->data
;
20 if (ieee80211_is_timing_measurement(skb
))
21 skb_dialog_token
= mgmt
->u
.action
.u
.wnm_timing_msr
.dialog_token
;
23 skb_dialog_token
= mgmt
->u
.action
.u
.ftm
.dialog_token
;
25 if ((ether_addr_equal(mgmt
->sa
, addr
) ||
26 ether_addr_equal(mgmt
->da
, addr
)) &&
27 skb_dialog_token
== dialog_token
)
33 static struct sk_buff
*iwl_mvm_time_sync_find_skb(struct iwl_mvm
*mvm
, u8
*addr
,
38 /* The queue is expected to have only one SKB. If there are other SKBs
39 * in the queue, they did not get a time sync notification and are
40 * probably obsolete by now, so drop them.
42 while ((skb
= skb_dequeue(&mvm
->time_sync
.frame_list
))) {
43 if (iwl_mvm_is_skb_match(skb
, addr
, dialog_token
))
53 static u64
iwl_mvm_get_64_bit(__le32 high
, __le32 low
)
55 return ((u64
)le32_to_cpu(high
) << 32) | le32_to_cpu(low
);
58 void iwl_mvm_time_sync_msmt_event(struct iwl_mvm
*mvm
,
59 struct iwl_rx_cmd_buffer
*rxb
)
61 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
62 struct iwl_time_msmt_notify
*notif
= (void *)pkt
->data
;
63 struct ieee80211_rx_status
*rx_status
;
64 struct skb_shared_hwtstamps
*shwt
;
67 iwl_mvm_time_sync_find_skb(mvm
, notif
->peer_addr
,
68 le32_to_cpu(notif
->dialog_token
));
72 IWL_DEBUG_INFO(mvm
, "Time sync event but no pending skb\n");
76 ts_10ns
= iwl_mvm_get_64_bit(notif
->t2_hi
, notif
->t2_lo
);
77 adj_time
= iwl_mvm_ptp_get_adj_time(mvm
, ts_10ns
* 10);
78 shwt
= skb_hwtstamps(skb
);
79 shwt
->hwtstamp
= ktime_set(0, adj_time
);
81 ts_10ns
= iwl_mvm_get_64_bit(notif
->t3_hi
, notif
->t3_lo
);
82 adj_time
= iwl_mvm_ptp_get_adj_time(mvm
, ts_10ns
* 10);
83 rx_status
= IEEE80211_SKB_RXCB(skb
);
84 rx_status
->ack_tx_hwtstamp
= ktime_set(0, adj_time
);
87 "Time sync: RX event - report frame t2=%llu t3=%llu\n",
88 ktime_to_ns(shwt
->hwtstamp
),
89 ktime_to_ns(rx_status
->ack_tx_hwtstamp
));
90 ieee80211_rx_napi(mvm
->hw
, NULL
, skb
, NULL
);
93 void iwl_mvm_time_sync_msmt_confirm_event(struct iwl_mvm
*mvm
,
94 struct iwl_rx_cmd_buffer
*rxb
)
96 struct iwl_rx_packet
*pkt
= rxb_addr(rxb
);
97 struct iwl_time_msmt_cfm_notify
*notif
= (void *)pkt
->data
;
98 struct ieee80211_tx_status status
= {};
99 struct skb_shared_hwtstamps
*shwt
;
100 u64 ts_10ns
, adj_time
;
103 iwl_mvm_time_sync_find_skb(mvm
, notif
->peer_addr
,
104 le32_to_cpu(notif
->dialog_token
));
107 IWL_DEBUG_INFO(mvm
, "Time sync confirm but no pending skb\n");
111 ts_10ns
= iwl_mvm_get_64_bit(notif
->t1_hi
, notif
->t1_lo
);
112 adj_time
= iwl_mvm_ptp_get_adj_time(mvm
, ts_10ns
* 10);
113 shwt
= skb_hwtstamps(status
.skb
);
114 shwt
->hwtstamp
= ktime_set(0, adj_time
);
116 ts_10ns
= iwl_mvm_get_64_bit(notif
->t4_hi
, notif
->t4_lo
);
117 adj_time
= iwl_mvm_ptp_get_adj_time(mvm
, ts_10ns
* 10);
118 status
.info
= IEEE80211_SKB_CB(status
.skb
);
119 status
.ack_hwtstamp
= ktime_set(0, adj_time
);
122 "Time sync: TX event - report frame t1=%llu t4=%llu\n",
123 ktime_to_ns(shwt
->hwtstamp
),
124 ktime_to_ns(status
.ack_hwtstamp
));
125 ieee80211_tx_status_ext(mvm
->hw
, &status
);
128 int iwl_mvm_time_sync_config(struct iwl_mvm
*mvm
, const u8
*addr
, u32 protocols
)
130 struct iwl_time_sync_cfg_cmd cmd
= {};
133 lockdep_assert_held(&mvm
->mutex
);
135 if (!fw_has_capa(&mvm
->fw
->ucode_capa
,
136 IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM
))
139 /* The fw only supports one peer. We do allow reconfiguration of the
140 * same peer for cases of fw reset etc.
142 if (mvm
->time_sync
.active
&&
143 !ether_addr_equal(addr
, mvm
->time_sync
.peer_addr
)) {
144 IWL_DEBUG_INFO(mvm
, "Time sync: reject config for peer: %pM\n",
149 if (protocols
& ~(IWL_TIME_SYNC_PROTOCOL_TM
|
150 IWL_TIME_SYNC_PROTOCOL_FTM
))
153 cmd
.protocols
= cpu_to_le32(protocols
);
155 ether_addr_copy(cmd
.peer_addr
, addr
);
157 err
= iwl_mvm_send_cmd_pdu(mvm
,
158 WIDE_ID(DATA_PATH_GROUP
,
159 WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD
),
160 0, sizeof(cmd
), &cmd
);
162 IWL_ERR(mvm
, "Failed to send time sync cfg cmd: %d\n", err
);
164 mvm
->time_sync
.active
= protocols
!= 0;
165 ether_addr_copy(mvm
->time_sync
.peer_addr
, addr
);
166 IWL_DEBUG_INFO(mvm
, "Time sync: set peer addr=%pM\n", addr
);
169 if (!mvm
->time_sync
.active
)
170 skb_queue_purge(&mvm
->time_sync
.frame_list
);