xref: /freebsd/contrib/processor-trace/libipt/src/pt_time.c (revision 85f87cf491bec6f90948a85b10f5523ea24db9e3)
174fe6c29SRuslan Bukin /*
2*85f87cf4SRuslan Bukin  * Copyright (c) 2014-2019, Intel Corporation
374fe6c29SRuslan Bukin  *
474fe6c29SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin  * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin  *
774fe6c29SRuslan Bukin  *  * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin  *  * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin  *    and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin  *  * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin  *    may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin  *    without specific prior written permission.
1574fe6c29SRuslan Bukin  *
1674fe6c29SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin  * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin  */
2874fe6c29SRuslan Bukin 
2974fe6c29SRuslan Bukin #include "pt_time.h"
3074fe6c29SRuslan Bukin #include "pt_opcodes.h"
3174fe6c29SRuslan Bukin 
3274fe6c29SRuslan Bukin #include "intel-pt.h"
3374fe6c29SRuslan Bukin 
3474fe6c29SRuslan Bukin #include <string.h>
3574fe6c29SRuslan Bukin #include <limits.h>
3674fe6c29SRuslan Bukin 
3774fe6c29SRuslan Bukin 
pt_time_init(struct pt_time * time)3874fe6c29SRuslan Bukin void pt_time_init(struct pt_time *time)
3974fe6c29SRuslan Bukin {
4074fe6c29SRuslan Bukin 	if (!time)
4174fe6c29SRuslan Bukin 		return;
4274fe6c29SRuslan Bukin 
4374fe6c29SRuslan Bukin 	memset(time, 0, sizeof(*time));
4474fe6c29SRuslan Bukin }
4574fe6c29SRuslan Bukin 
pt_time_query_tsc(uint64_t * tsc,uint32_t * lost_mtc,uint32_t * lost_cyc,const struct pt_time * time)4674fe6c29SRuslan Bukin int pt_time_query_tsc(uint64_t *tsc, uint32_t *lost_mtc,
4774fe6c29SRuslan Bukin 		      uint32_t *lost_cyc, const struct pt_time *time)
4874fe6c29SRuslan Bukin {
4974fe6c29SRuslan Bukin 	if (!tsc || !time)
5074fe6c29SRuslan Bukin 		return -pte_internal;
5174fe6c29SRuslan Bukin 
5274fe6c29SRuslan Bukin 	*tsc = time->tsc;
5374fe6c29SRuslan Bukin 
5474fe6c29SRuslan Bukin 	if (lost_mtc)
5574fe6c29SRuslan Bukin 		*lost_mtc = time->lost_mtc;
5674fe6c29SRuslan Bukin 	if (lost_cyc)
5774fe6c29SRuslan Bukin 		*lost_cyc = time->lost_cyc;
5874fe6c29SRuslan Bukin 
5974fe6c29SRuslan Bukin 	if (!time->have_tsc)
6074fe6c29SRuslan Bukin 		return -pte_no_time;
6174fe6c29SRuslan Bukin 
6274fe6c29SRuslan Bukin 	return 0;
6374fe6c29SRuslan Bukin }
6474fe6c29SRuslan Bukin 
pt_time_query_cbr(uint32_t * cbr,const struct pt_time * time)6574fe6c29SRuslan Bukin int pt_time_query_cbr(uint32_t *cbr, const struct pt_time *time)
6674fe6c29SRuslan Bukin {
6774fe6c29SRuslan Bukin 	if (!cbr || !time)
6874fe6c29SRuslan Bukin 		return -pte_internal;
6974fe6c29SRuslan Bukin 
7074fe6c29SRuslan Bukin 	if (!time->have_cbr)
7174fe6c29SRuslan Bukin 		return -pte_no_cbr;
7274fe6c29SRuslan Bukin 
7374fe6c29SRuslan Bukin 	*cbr = time->cbr;
7474fe6c29SRuslan Bukin 
7574fe6c29SRuslan Bukin 	return 0;
7674fe6c29SRuslan Bukin }
7774fe6c29SRuslan Bukin 
7874fe6c29SRuslan Bukin /* Compute the distance between two CTC sources.
7974fe6c29SRuslan Bukin  *
8074fe6c29SRuslan Bukin  * We adjust a single wrap-around but fail if the distance is bigger than that.
8174fe6c29SRuslan Bukin  *
8274fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
8374fe6c29SRuslan Bukin  */
pt_time_ctc_delta(uint32_t * ctc_delta,uint32_t ctc,uint32_t last_ctc,const struct pt_config * config)8474fe6c29SRuslan Bukin static int pt_time_ctc_delta(uint32_t *ctc_delta, uint32_t ctc,
8574fe6c29SRuslan Bukin 			     uint32_t last_ctc, const struct pt_config *config)
8674fe6c29SRuslan Bukin {
8774fe6c29SRuslan Bukin 	if (!config || !ctc_delta)
8874fe6c29SRuslan Bukin 		return -pte_internal;
8974fe6c29SRuslan Bukin 
9074fe6c29SRuslan Bukin 	/* Correct a single wrap-around.  If we lost enough MTCs to wrap
9174fe6c29SRuslan Bukin 	 * around twice, timing will be wrong until the next TSC.
9274fe6c29SRuslan Bukin 	 */
9374fe6c29SRuslan Bukin 	if (ctc < last_ctc) {
9474fe6c29SRuslan Bukin 		ctc += 1u << (config->mtc_freq + pt_pl_mtc_bit_size);
9574fe6c29SRuslan Bukin 
9674fe6c29SRuslan Bukin 		/* Since we only store the CTC between TMA/MTC or MTC/TMC a
9774fe6c29SRuslan Bukin 		 * single correction should suffice.
9874fe6c29SRuslan Bukin 		 */
9974fe6c29SRuslan Bukin 		if (ctc < last_ctc)
10074fe6c29SRuslan Bukin 			return -pte_bad_packet;
10174fe6c29SRuslan Bukin 	}
10274fe6c29SRuslan Bukin 
10374fe6c29SRuslan Bukin 	*ctc_delta = ctc - last_ctc;
10474fe6c29SRuslan Bukin 	return 0;
10574fe6c29SRuslan Bukin }
10674fe6c29SRuslan Bukin 
10774fe6c29SRuslan Bukin /* Translate CTC into the same unit as the FastCounter by multiplying with P.
10874fe6c29SRuslan Bukin  *
10974fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
11074fe6c29SRuslan Bukin  */
pt_time_ctc_fc(uint64_t * fc,uint64_t ctc,const struct pt_config * config)11174fe6c29SRuslan Bukin static int pt_time_ctc_fc(uint64_t *fc, uint64_t ctc,
11274fe6c29SRuslan Bukin 			  const struct pt_config *config)
11374fe6c29SRuslan Bukin {
11474fe6c29SRuslan Bukin 	uint32_t eax, ebx;
11574fe6c29SRuslan Bukin 
11674fe6c29SRuslan Bukin 	if (!fc || !config)
11774fe6c29SRuslan Bukin 		return -pte_internal;
11874fe6c29SRuslan Bukin 
11974fe6c29SRuslan Bukin 	eax = config->cpuid_0x15_eax;
12074fe6c29SRuslan Bukin 	ebx = config->cpuid_0x15_ebx;
12174fe6c29SRuslan Bukin 
12274fe6c29SRuslan Bukin 	/* Neither multiply nor divide by zero. */
12374fe6c29SRuslan Bukin 	if (!eax || !ebx)
12474fe6c29SRuslan Bukin 		return -pte_bad_config;
12574fe6c29SRuslan Bukin 
12674fe6c29SRuslan Bukin 	*fc = (ctc * ebx) / eax;
12774fe6c29SRuslan Bukin 	return 0;
12874fe6c29SRuslan Bukin }
12974fe6c29SRuslan Bukin 
pt_time_update_tsc(struct pt_time * time,const struct pt_packet_tsc * packet,const struct pt_config * config)13074fe6c29SRuslan Bukin int pt_time_update_tsc(struct pt_time *time,
13174fe6c29SRuslan Bukin 		       const struct pt_packet_tsc *packet,
13274fe6c29SRuslan Bukin 		       const struct pt_config *config)
13374fe6c29SRuslan Bukin {
13474fe6c29SRuslan Bukin 	(void) config;
13574fe6c29SRuslan Bukin 
13674fe6c29SRuslan Bukin 	if (!time || !packet)
13774fe6c29SRuslan Bukin 		return -pte_internal;
13874fe6c29SRuslan Bukin 
13974fe6c29SRuslan Bukin 	time->have_tsc = 1;
14074fe6c29SRuslan Bukin 	time->have_tma = 0;
14174fe6c29SRuslan Bukin 	time->have_mtc = 0;
14274fe6c29SRuslan Bukin 	time->tsc = time->base = packet->tsc;
14374fe6c29SRuslan Bukin 	time->ctc = 0;
14474fe6c29SRuslan Bukin 	time->fc = 0ull;
14574fe6c29SRuslan Bukin 
14674fe6c29SRuslan Bukin 	/* We got the full time; we recover from previous losses. */
14774fe6c29SRuslan Bukin 	time->lost_mtc = 0;
14874fe6c29SRuslan Bukin 	time->lost_cyc = 0;
14974fe6c29SRuslan Bukin 
15074fe6c29SRuslan Bukin 	return 0;
15174fe6c29SRuslan Bukin }
15274fe6c29SRuslan Bukin 
pt_time_update_cbr(struct pt_time * time,const struct pt_packet_cbr * packet,const struct pt_config * config)15374fe6c29SRuslan Bukin int pt_time_update_cbr(struct pt_time *time,
15474fe6c29SRuslan Bukin 		       const struct pt_packet_cbr *packet,
15574fe6c29SRuslan Bukin 		       const struct pt_config *config)
15674fe6c29SRuslan Bukin {
157*85f87cf4SRuslan Bukin 	uint8_t cbr;
158*85f87cf4SRuslan Bukin 
15974fe6c29SRuslan Bukin 	(void) config;
16074fe6c29SRuslan Bukin 
16174fe6c29SRuslan Bukin 	if (!time || !packet)
16274fe6c29SRuslan Bukin 		return -pte_internal;
16374fe6c29SRuslan Bukin 
164*85f87cf4SRuslan Bukin 	cbr = packet->ratio;
165*85f87cf4SRuslan Bukin 	if (!cbr)
166*85f87cf4SRuslan Bukin 		return -pte_bad_packet;
167*85f87cf4SRuslan Bukin 
16874fe6c29SRuslan Bukin 	time->have_cbr = 1;
169*85f87cf4SRuslan Bukin 	time->cbr = cbr;
17074fe6c29SRuslan Bukin 
17174fe6c29SRuslan Bukin 	return 0;
17274fe6c29SRuslan Bukin }
17374fe6c29SRuslan Bukin 
pt_time_update_tma(struct pt_time * time,const struct pt_packet_tma * packet,const struct pt_config * config)17474fe6c29SRuslan Bukin int pt_time_update_tma(struct pt_time *time,
17574fe6c29SRuslan Bukin 		       const struct pt_packet_tma *packet,
17674fe6c29SRuslan Bukin 		       const struct pt_config *config)
17774fe6c29SRuslan Bukin {
17874fe6c29SRuslan Bukin 	uint32_t ctc, mtc_freq, mtc_hi, ctc_mask;
17974fe6c29SRuslan Bukin 	uint64_t fc;
18074fe6c29SRuslan Bukin 
18174fe6c29SRuslan Bukin 	if (!time || !packet || !config)
18274fe6c29SRuslan Bukin 		return -pte_internal;
18374fe6c29SRuslan Bukin 
18474fe6c29SRuslan Bukin 	/* Without a TSC something is seriously wrong. */
18574fe6c29SRuslan Bukin 	if (!time->have_tsc)
18674fe6c29SRuslan Bukin 		return -pte_bad_context;
18774fe6c29SRuslan Bukin 
18874fe6c29SRuslan Bukin 	/* We shouldn't have more than one TMA per TSC. */
18974fe6c29SRuslan Bukin 	if (time->have_tma)
19074fe6c29SRuslan Bukin 		return -pte_bad_context;
19174fe6c29SRuslan Bukin 
19274fe6c29SRuslan Bukin 	/* We're ignoring MTC between TSC and TMA. */
19374fe6c29SRuslan Bukin 	if (time->have_mtc)
19474fe6c29SRuslan Bukin 		return -pte_internal;
19574fe6c29SRuslan Bukin 
19674fe6c29SRuslan Bukin 	ctc = packet->ctc;
19774fe6c29SRuslan Bukin 	fc = packet->fc;
19874fe6c29SRuslan Bukin 
19974fe6c29SRuslan Bukin 	mtc_freq = config->mtc_freq;
20074fe6c29SRuslan Bukin 	mtc_hi = mtc_freq + pt_pl_mtc_bit_size;
20174fe6c29SRuslan Bukin 
20274fe6c29SRuslan Bukin 	/* A mask for the relevant CTC bits ignoring high-order bits that are
20374fe6c29SRuslan Bukin 	 * not provided by MTC.
20474fe6c29SRuslan Bukin 	 */
20574fe6c29SRuslan Bukin 	ctc_mask = (1u << mtc_hi) - 1u;
20674fe6c29SRuslan Bukin 
20774fe6c29SRuslan Bukin 	time->have_tma = 1;
20874fe6c29SRuslan Bukin 	time->base -= fc;
20974fe6c29SRuslan Bukin 	time->fc += fc;
21074fe6c29SRuslan Bukin 
21174fe6c29SRuslan Bukin 	/* If the MTC frequency is low enough that TMA provides the full CTC
21274fe6c29SRuslan Bukin 	 * value, we can use the TMA as an MTC.
21374fe6c29SRuslan Bukin 	 *
21474fe6c29SRuslan Bukin 	 * If it isn't, we will estimate the preceding MTC based on the CTC bits
21574fe6c29SRuslan Bukin 	 * the TMA provides at the next MTC.  We forget about the previous MTC
21674fe6c29SRuslan Bukin 	 * in this case.
21774fe6c29SRuslan Bukin 	 *
21874fe6c29SRuslan Bukin 	 * If no MTC packets are dropped around TMA, we will estimate the
21974fe6c29SRuslan Bukin 	 * forgotten value again at the next MTC.
22074fe6c29SRuslan Bukin 	 *
22174fe6c29SRuslan Bukin 	 * If MTC packets are dropped, we can't really tell where in this
22274fe6c29SRuslan Bukin 	 * extended MTC period the TSC occurred.  The estimation will place it
22374fe6c29SRuslan Bukin 	 * right before the next MTC.
22474fe6c29SRuslan Bukin 	 */
22574fe6c29SRuslan Bukin 	if (mtc_hi <= pt_pl_tma_ctc_bit_size)
22674fe6c29SRuslan Bukin 		time->have_mtc = 1;
22774fe6c29SRuslan Bukin 
22874fe6c29SRuslan Bukin 	/* In both cases, we store the TMA's CTC bits until the next MTC. */
22974fe6c29SRuslan Bukin 	time->ctc = time->ctc_cyc = ctc & ctc_mask;
23074fe6c29SRuslan Bukin 
23174fe6c29SRuslan Bukin 	return 0;
23274fe6c29SRuslan Bukin }
23374fe6c29SRuslan Bukin 
pt_time_update_mtc(struct pt_time * time,const struct pt_packet_mtc * packet,const struct pt_config * config)23474fe6c29SRuslan Bukin int pt_time_update_mtc(struct pt_time *time,
23574fe6c29SRuslan Bukin 		       const struct pt_packet_mtc *packet,
23674fe6c29SRuslan Bukin 		       const struct pt_config *config)
23774fe6c29SRuslan Bukin {
23874fe6c29SRuslan Bukin 	uint32_t last_ctc, ctc, ctc_delta;
23974fe6c29SRuslan Bukin 	uint64_t tsc, base;
24074fe6c29SRuslan Bukin 	uint8_t mtc_freq;
24174fe6c29SRuslan Bukin 	int errcode, have_tsc, have_tma, have_mtc;
24274fe6c29SRuslan Bukin 
24374fe6c29SRuslan Bukin 	if (!time || !packet || !config)
24474fe6c29SRuslan Bukin 		return -pte_internal;
24574fe6c29SRuslan Bukin 
24674fe6c29SRuslan Bukin 	have_tsc = time->have_tsc;
24774fe6c29SRuslan Bukin 	have_tma = time->have_tma;
24874fe6c29SRuslan Bukin 	have_mtc = time->have_mtc;
24974fe6c29SRuslan Bukin 
25074fe6c29SRuslan Bukin 	/* We ignore MTCs between TSC and TMA to avoid apparent CTC overflows.
25174fe6c29SRuslan Bukin 	 *
25274fe6c29SRuslan Bukin 	 * Later MTCs will ensure that no time is lost - provided TMA provides
25374fe6c29SRuslan Bukin 	 * enough bits.  If TMA doesn't provide any of the MTC bits we may place
25474fe6c29SRuslan Bukin 	 * the TSC into the wrong MTC period.
25574fe6c29SRuslan Bukin 	 */
25674fe6c29SRuslan Bukin 	if (have_tsc && !have_tma)
25774fe6c29SRuslan Bukin 		return 0;
25874fe6c29SRuslan Bukin 
25974fe6c29SRuslan Bukin 	base = time->base;
26074fe6c29SRuslan Bukin 	last_ctc = time->ctc;
26174fe6c29SRuslan Bukin 	mtc_freq = config->mtc_freq;
26274fe6c29SRuslan Bukin 
263*85f87cf4SRuslan Bukin 	ctc = (uint32_t) packet->ctc << mtc_freq;
26474fe6c29SRuslan Bukin 
26574fe6c29SRuslan Bukin 	/* Store our CTC value if we have or would have reset FC. */
26674fe6c29SRuslan Bukin 	if (time->fc || time->lost_cyc || !have_mtc)
26774fe6c29SRuslan Bukin 		time->ctc_cyc = ctc;
26874fe6c29SRuslan Bukin 
26974fe6c29SRuslan Bukin 	/* Prepare for the next packet in case we error out below. */
27074fe6c29SRuslan Bukin 	time->have_mtc = 1;
27174fe6c29SRuslan Bukin 	time->fc = 0ull;
27274fe6c29SRuslan Bukin 	time->ctc = ctc;
27374fe6c29SRuslan Bukin 
27474fe6c29SRuslan Bukin 	/* We recover from previous CYC losses. */
27574fe6c29SRuslan Bukin 	time->lost_cyc = 0;
27674fe6c29SRuslan Bukin 
27774fe6c29SRuslan Bukin 	/* Avoid a big jump when we see the first MTC with an arbitrary CTC
27874fe6c29SRuslan Bukin 	 * payload.
27974fe6c29SRuslan Bukin 	 */
28074fe6c29SRuslan Bukin 	if (!have_mtc) {
28174fe6c29SRuslan Bukin 		uint32_t ctc_lo, ctc_hi;
28274fe6c29SRuslan Bukin 
28374fe6c29SRuslan Bukin 		/* If we have not seen a TMA, we ignore this first MTC.
28474fe6c29SRuslan Bukin 		 *
28574fe6c29SRuslan Bukin 		 * We have no idea where in this MTC period tracing started.
28674fe6c29SRuslan Bukin 		 * We could lose an entire MTC period or just a tiny fraction.
28774fe6c29SRuslan Bukin 		 *
28874fe6c29SRuslan Bukin 		 * On the other hand, if we assumed a previous MTC value, we
28974fe6c29SRuslan Bukin 		 * might make just the same error.
29074fe6c29SRuslan Bukin 		 */
29174fe6c29SRuslan Bukin 		if (!have_tma)
29274fe6c29SRuslan Bukin 			return 0;
29374fe6c29SRuslan Bukin 
29474fe6c29SRuslan Bukin 		/* The TMA's CTC value didn't provide enough bits - otherwise,
29574fe6c29SRuslan Bukin 		 * we would have treated the TMA as an MTC.
29674fe6c29SRuslan Bukin 		 */
297*85f87cf4SRuslan Bukin 		if (last_ctc & ~(uint32_t) pt_pl_tma_ctc_mask)
29874fe6c29SRuslan Bukin 			return -pte_internal;
29974fe6c29SRuslan Bukin 
30074fe6c29SRuslan Bukin 		/* Split this MTC's CTC value into low and high parts with
30174fe6c29SRuslan Bukin 		 * respect to the bits provided by TMA.
30274fe6c29SRuslan Bukin 		 */
303*85f87cf4SRuslan Bukin 		ctc_lo = ctc & (uint32_t) pt_pl_tma_ctc_mask;
304*85f87cf4SRuslan Bukin 		ctc_hi = ctc & ~(uint32_t) pt_pl_tma_ctc_mask;
30574fe6c29SRuslan Bukin 
30674fe6c29SRuslan Bukin 		/* We estimate the high-order CTC bits that are not provided by
30774fe6c29SRuslan Bukin 		 * TMA based on the CTC bits provided by this MTC.
30874fe6c29SRuslan Bukin 		 *
30974fe6c29SRuslan Bukin 		 * We assume that no MTC packets were dropped around TMA.  If
31074fe6c29SRuslan Bukin 		 * there are, we might place the TSC into the wrong MTC period
31174fe6c29SRuslan Bukin 		 * depending on how many CTC bits TMA provides and how many MTC
31274fe6c29SRuslan Bukin 		 * packets were dropped.
31374fe6c29SRuslan Bukin 		 *
31474fe6c29SRuslan Bukin 		 * Note that we may underflow which results in more bits to be
31574fe6c29SRuslan Bukin 		 * set than MTC packets may provide.  Drop those extra bits.
31674fe6c29SRuslan Bukin 		 */
31774fe6c29SRuslan Bukin 		if (ctc_lo < last_ctc) {
31874fe6c29SRuslan Bukin 			ctc_hi -= 1u << pt_pl_tma_ctc_bit_size;
319*85f87cf4SRuslan Bukin 			ctc_hi &= (uint32_t) pt_pl_mtc_mask << mtc_freq;
32074fe6c29SRuslan Bukin 		}
32174fe6c29SRuslan Bukin 
32274fe6c29SRuslan Bukin 		last_ctc |= ctc_hi;
32374fe6c29SRuslan Bukin 	}
32474fe6c29SRuslan Bukin 
32574fe6c29SRuslan Bukin 	errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
32674fe6c29SRuslan Bukin 	if (errcode < 0) {
32774fe6c29SRuslan Bukin 		time->lost_mtc += 1;
32874fe6c29SRuslan Bukin 		return errcode;
32974fe6c29SRuslan Bukin 	}
33074fe6c29SRuslan Bukin 
33174fe6c29SRuslan Bukin 	errcode = pt_time_ctc_fc(&tsc, ctc_delta, config);
33274fe6c29SRuslan Bukin 	if (errcode < 0)
33374fe6c29SRuslan Bukin 		return errcode;
33474fe6c29SRuslan Bukin 
33574fe6c29SRuslan Bukin 	base += tsc;
33674fe6c29SRuslan Bukin 	time->tsc = time->base = base;
33774fe6c29SRuslan Bukin 
33874fe6c29SRuslan Bukin 	return 0;
33974fe6c29SRuslan Bukin }
34074fe6c29SRuslan Bukin 
34174fe6c29SRuslan Bukin /* Adjust a CYC packet's payload spanning multiple MTC periods.
34274fe6c29SRuslan Bukin  *
34374fe6c29SRuslan Bukin  * CYC packets measure the Fast Counter since the last CYC(-eligible) packet.
34474fe6c29SRuslan Bukin  * Depending on the CYC threshold, we may not get a CYC for each MTC, so a CYC
34574fe6c29SRuslan Bukin  * period may overlap with or even span multiple MTC periods.
34674fe6c29SRuslan Bukin  *
34774fe6c29SRuslan Bukin  * We can't do much about the overlap case without examining all packets in
34874fe6c29SRuslan Bukin  * the respective periods.  We leave this as expected imprecision.
34974fe6c29SRuslan Bukin  *
35074fe6c29SRuslan Bukin  * If we find a CYC packet to span multiple MTC packets, though, we try to
35174fe6c29SRuslan Bukin  * approximate the portion for the current MTC period by subtracting the
35274fe6c29SRuslan Bukin  * estimated portion for previous MTC periods using calibration information.
35374fe6c29SRuslan Bukin  *
35474fe6c29SRuslan Bukin  * We only consider MTC.  For the first CYC after TSC, the corresponding TMA
35574fe6c29SRuslan Bukin  * will contain the Fast Counter at TSC.
35674fe6c29SRuslan Bukin  *
35774fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
35874fe6c29SRuslan Bukin  */
pt_time_adjust_cyc(uint64_t * cyc,const struct pt_time * time,const struct pt_config * config,uint64_t fcr)35974fe6c29SRuslan Bukin static int pt_time_adjust_cyc(uint64_t *cyc, const struct pt_time *time,
36074fe6c29SRuslan Bukin 			      const struct pt_config *config, uint64_t fcr)
36174fe6c29SRuslan Bukin {
36274fe6c29SRuslan Bukin 	uint32_t last_ctc, ctc, ctc_delta;
36374fe6c29SRuslan Bukin 	uint64_t fc, total_cyc, old_cyc;
36474fe6c29SRuslan Bukin 	int errcode;
36574fe6c29SRuslan Bukin 
36674fe6c29SRuslan Bukin 	if (!time || !config || !fcr)
36774fe6c29SRuslan Bukin 		return -pte_internal;
36874fe6c29SRuslan Bukin 
36974fe6c29SRuslan Bukin 	last_ctc = time->ctc_cyc;
37074fe6c29SRuslan Bukin 	ctc = time->ctc;
37174fe6c29SRuslan Bukin 
37274fe6c29SRuslan Bukin 	/* There is nothing to do if this is the current MTC period. */
37374fe6c29SRuslan Bukin 	if (ctc == last_ctc)
37474fe6c29SRuslan Bukin 		return 0;
37574fe6c29SRuslan Bukin 
37674fe6c29SRuslan Bukin 	/* Calibration computes
37774fe6c29SRuslan Bukin 	 *
37874fe6c29SRuslan Bukin 	 *   fc  = (ctc_delta * cpuid[0x15].ebx) / cpuid[0x15].eax.
37974fe6c29SRuslan Bukin 	 *   fcr = (fc << pt_tcal_fcr_shr) / cyc
38074fe6c29SRuslan Bukin 	 *
38174fe6c29SRuslan Bukin 	 * So cyc = (fc << pt_tcal_fcr_shr) / fcr.
38274fe6c29SRuslan Bukin 	 */
38374fe6c29SRuslan Bukin 
38474fe6c29SRuslan Bukin 	errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
38574fe6c29SRuslan Bukin 	if (errcode < 0)
38674fe6c29SRuslan Bukin 		return errcode;
38774fe6c29SRuslan Bukin 
38874fe6c29SRuslan Bukin 	errcode = pt_time_ctc_fc(&fc, ctc_delta, config);
38974fe6c29SRuslan Bukin 	if (errcode < 0)
39074fe6c29SRuslan Bukin 		return errcode;
39174fe6c29SRuslan Bukin 
39274fe6c29SRuslan Bukin 	old_cyc = (fc << pt_tcal_fcr_shr) / fcr;
39374fe6c29SRuslan Bukin 	total_cyc = *cyc;
39474fe6c29SRuslan Bukin 
39574fe6c29SRuslan Bukin 	/* Make sure we don't wrap around.  If we would, attribute the entire
39674fe6c29SRuslan Bukin 	 * CYC payload to any previous MTC period.
39774fe6c29SRuslan Bukin 	 *
39874fe6c29SRuslan Bukin 	 * We lost an unknown portion of the CYC payload for the current MTC
39974fe6c29SRuslan Bukin 	 * period, but it's usually better to run too slow than too fast.
40074fe6c29SRuslan Bukin 	 */
40174fe6c29SRuslan Bukin 	if (total_cyc < old_cyc)
40274fe6c29SRuslan Bukin 		total_cyc = old_cyc;
40374fe6c29SRuslan Bukin 
40474fe6c29SRuslan Bukin 	*cyc = total_cyc - old_cyc;
40574fe6c29SRuslan Bukin 	return 0;
40674fe6c29SRuslan Bukin }
40774fe6c29SRuslan Bukin 
pt_time_update_cyc(struct pt_time * time,const struct pt_packet_cyc * packet,const struct pt_config * config,uint64_t fcr)40874fe6c29SRuslan Bukin int pt_time_update_cyc(struct pt_time *time,
40974fe6c29SRuslan Bukin 		       const struct pt_packet_cyc *packet,
41074fe6c29SRuslan Bukin 		       const struct pt_config *config, uint64_t fcr)
41174fe6c29SRuslan Bukin {
41274fe6c29SRuslan Bukin 	uint64_t cyc, fc;
41374fe6c29SRuslan Bukin 
41474fe6c29SRuslan Bukin 	if (!time || !packet || !config)
41574fe6c29SRuslan Bukin 		return -pte_internal;
41674fe6c29SRuslan Bukin 
41774fe6c29SRuslan Bukin 	if (!fcr) {
41874fe6c29SRuslan Bukin 		time->lost_cyc += 1;
41974fe6c29SRuslan Bukin 		return 0;
42074fe6c29SRuslan Bukin 	}
42174fe6c29SRuslan Bukin 
42274fe6c29SRuslan Bukin 	cyc = packet->value;
42374fe6c29SRuslan Bukin 	fc = time->fc;
42474fe6c29SRuslan Bukin 	if (!fc) {
42574fe6c29SRuslan Bukin 		int errcode;
42674fe6c29SRuslan Bukin 
42774fe6c29SRuslan Bukin 		errcode = pt_time_adjust_cyc(&cyc, time, config, fcr);
42874fe6c29SRuslan Bukin 		if (errcode < 0)
42974fe6c29SRuslan Bukin 			return errcode;
43074fe6c29SRuslan Bukin 	}
43174fe6c29SRuslan Bukin 
43274fe6c29SRuslan Bukin 	fc += (cyc * fcr) >> pt_tcal_fcr_shr;
43374fe6c29SRuslan Bukin 
43474fe6c29SRuslan Bukin 	time->fc = fc;
43574fe6c29SRuslan Bukin 	time->tsc = time->base + fc;
43674fe6c29SRuslan Bukin 
43774fe6c29SRuslan Bukin 	return 0;
43874fe6c29SRuslan Bukin }
43974fe6c29SRuslan Bukin 
pt_tcal_init(struct pt_time_cal * tcal)44074fe6c29SRuslan Bukin void pt_tcal_init(struct pt_time_cal *tcal)
44174fe6c29SRuslan Bukin {
44274fe6c29SRuslan Bukin 	if (!tcal)
44374fe6c29SRuslan Bukin 		return;
44474fe6c29SRuslan Bukin 
44574fe6c29SRuslan Bukin 	memset(tcal, 0, sizeof(*tcal));
44674fe6c29SRuslan Bukin 
44774fe6c29SRuslan Bukin 	tcal->min_fcr = UINT64_MAX;
44874fe6c29SRuslan Bukin }
44974fe6c29SRuslan Bukin 
pt_tcal_have_fcr(const struct pt_time_cal * tcal)45074fe6c29SRuslan Bukin static int pt_tcal_have_fcr(const struct pt_time_cal *tcal)
45174fe6c29SRuslan Bukin {
45274fe6c29SRuslan Bukin 	if (!tcal)
45374fe6c29SRuslan Bukin 		return 0;
45474fe6c29SRuslan Bukin 
45574fe6c29SRuslan Bukin 	return (tcal->min_fcr <= tcal->max_fcr);
45674fe6c29SRuslan Bukin }
45774fe6c29SRuslan Bukin 
pt_tcal_fcr(uint64_t * fcr,const struct pt_time_cal * tcal)45874fe6c29SRuslan Bukin int pt_tcal_fcr(uint64_t *fcr, const struct pt_time_cal *tcal)
45974fe6c29SRuslan Bukin {
46074fe6c29SRuslan Bukin 	if (!fcr || !tcal)
46174fe6c29SRuslan Bukin 		return -pte_internal;
46274fe6c29SRuslan Bukin 
46374fe6c29SRuslan Bukin 	if (!pt_tcal_have_fcr(tcal))
46474fe6c29SRuslan Bukin 		return -pte_no_time;
46574fe6c29SRuslan Bukin 
46674fe6c29SRuslan Bukin 	*fcr = tcal->fcr;
46774fe6c29SRuslan Bukin 
46874fe6c29SRuslan Bukin 	return 0;
46974fe6c29SRuslan Bukin }
47074fe6c29SRuslan Bukin 
pt_tcal_set_fcr(struct pt_time_cal * tcal,uint64_t fcr)47174fe6c29SRuslan Bukin int pt_tcal_set_fcr(struct pt_time_cal *tcal, uint64_t fcr)
47274fe6c29SRuslan Bukin {
47374fe6c29SRuslan Bukin 	if (!tcal)
47474fe6c29SRuslan Bukin 		return -pte_internal;
47574fe6c29SRuslan Bukin 
47674fe6c29SRuslan Bukin 	tcal->fcr = fcr;
47774fe6c29SRuslan Bukin 
47874fe6c29SRuslan Bukin 	if (fcr < tcal->min_fcr)
47974fe6c29SRuslan Bukin 		tcal->min_fcr = fcr;
48074fe6c29SRuslan Bukin 
48174fe6c29SRuslan Bukin 	if (fcr > tcal->max_fcr)
48274fe6c29SRuslan Bukin 		tcal->max_fcr = fcr;
48374fe6c29SRuslan Bukin 
48474fe6c29SRuslan Bukin 	return 0;
48574fe6c29SRuslan Bukin }
48674fe6c29SRuslan Bukin 
pt_tcal_update_psb(struct pt_time_cal * tcal,const struct pt_config * config)487*85f87cf4SRuslan Bukin int pt_tcal_update_psb(struct pt_time_cal *tcal,
488*85f87cf4SRuslan Bukin 		       const struct pt_config *config)
489*85f87cf4SRuslan Bukin {
490*85f87cf4SRuslan Bukin 	if (!tcal || !config)
491*85f87cf4SRuslan Bukin 		return -pte_internal;
492*85f87cf4SRuslan Bukin 
493*85f87cf4SRuslan Bukin 	if (config->errata.skl168)
494*85f87cf4SRuslan Bukin 		tcal->check_skl168 = 1;
495*85f87cf4SRuslan Bukin 
496*85f87cf4SRuslan Bukin 	return 0;
497*85f87cf4SRuslan Bukin }
498*85f87cf4SRuslan Bukin 
pt_tcal_update_tsc(struct pt_time_cal * tcal,const struct pt_packet_tsc * packet,const struct pt_config * config)49974fe6c29SRuslan Bukin int pt_tcal_update_tsc(struct pt_time_cal *tcal,
50074fe6c29SRuslan Bukin 		      const struct pt_packet_tsc *packet,
50174fe6c29SRuslan Bukin 		      const struct pt_config *config)
50274fe6c29SRuslan Bukin {
50374fe6c29SRuslan Bukin 	(void) config;
50474fe6c29SRuslan Bukin 
50574fe6c29SRuslan Bukin 	if (!tcal || !packet)
50674fe6c29SRuslan Bukin 		return -pte_internal;
50774fe6c29SRuslan Bukin 
50874fe6c29SRuslan Bukin 	/* A TSC outside of PSB+ may indicate loss of time.  We do not use it
50974fe6c29SRuslan Bukin 	 * for calibration.  We store the TSC value for calibration at the next
51074fe6c29SRuslan Bukin 	 * TSC in PSB+, though.
51174fe6c29SRuslan Bukin 	 */
51274fe6c29SRuslan Bukin 	tcal->tsc = packet->tsc;
51374fe6c29SRuslan Bukin 	tcal->cyc_tsc = 0ull;
51474fe6c29SRuslan Bukin 
51574fe6c29SRuslan Bukin 	return 0;
51674fe6c29SRuslan Bukin }
51774fe6c29SRuslan Bukin 
pt_tcal_header_tsc(struct pt_time_cal * tcal,const struct pt_packet_tsc * packet,const struct pt_config * config)51874fe6c29SRuslan Bukin int pt_tcal_header_tsc(struct pt_time_cal *tcal,
51974fe6c29SRuslan Bukin 		      const struct pt_packet_tsc *packet,
52074fe6c29SRuslan Bukin 		      const struct pt_config *config)
52174fe6c29SRuslan Bukin {
52274fe6c29SRuslan Bukin 	uint64_t tsc, last_tsc, tsc_delta, cyc, fcr;
52374fe6c29SRuslan Bukin 
52474fe6c29SRuslan Bukin 	(void) config;
52574fe6c29SRuslan Bukin 
52674fe6c29SRuslan Bukin 	if (!tcal || !packet)
52774fe6c29SRuslan Bukin 		return -pte_internal;
52874fe6c29SRuslan Bukin 
52974fe6c29SRuslan Bukin 	last_tsc = tcal->tsc;
53074fe6c29SRuslan Bukin 	cyc = tcal->cyc_tsc;
53174fe6c29SRuslan Bukin 
53274fe6c29SRuslan Bukin 	tsc = packet->tsc;
53374fe6c29SRuslan Bukin 
53474fe6c29SRuslan Bukin 	tcal->tsc = tsc;
53574fe6c29SRuslan Bukin 	tcal->cyc_tsc = 0ull;
53674fe6c29SRuslan Bukin 
53774fe6c29SRuslan Bukin 	if (!last_tsc || !cyc)
53874fe6c29SRuslan Bukin 		return 0;
53974fe6c29SRuslan Bukin 
540*85f87cf4SRuslan Bukin 	/* Prefer MTC over TSC for calibration. */
541*85f87cf4SRuslan Bukin 	if (tcal->have_mtc)
542*85f87cf4SRuslan Bukin 		return 0;
543*85f87cf4SRuslan Bukin 
54474fe6c29SRuslan Bukin 	/* Correct a single wrap-around. */
54574fe6c29SRuslan Bukin 	if (tsc < last_tsc) {
54674fe6c29SRuslan Bukin 		tsc += 1ull << pt_pl_tsc_bit_size;
54774fe6c29SRuslan Bukin 
54874fe6c29SRuslan Bukin 		if (tsc < last_tsc)
54974fe6c29SRuslan Bukin 			return -pte_bad_packet;
55074fe6c29SRuslan Bukin 	}
55174fe6c29SRuslan Bukin 
55274fe6c29SRuslan Bukin 	tsc_delta = tsc - last_tsc;
55374fe6c29SRuslan Bukin 
55474fe6c29SRuslan Bukin 	/* We shift the nominator to improve rounding precision.
55574fe6c29SRuslan Bukin 	 *
55674fe6c29SRuslan Bukin 	 * Since we're only collecting the CYCs between two TSC, we shouldn't
55774fe6c29SRuslan Bukin 	 * overflow.  Let's rather fail than overflow.
55874fe6c29SRuslan Bukin 	 */
55974fe6c29SRuslan Bukin 	if (tsc_delta & ~(~0ull >> pt_tcal_fcr_shr))
56074fe6c29SRuslan Bukin 		return -pte_internal;
56174fe6c29SRuslan Bukin 
56274fe6c29SRuslan Bukin 	fcr = (tsc_delta << pt_tcal_fcr_shr) / cyc;
56374fe6c29SRuslan Bukin 
56474fe6c29SRuslan Bukin 	return pt_tcal_set_fcr(tcal, fcr);
56574fe6c29SRuslan Bukin }
56674fe6c29SRuslan Bukin 
pt_tcal_update_cbr(struct pt_time_cal * tcal,const struct pt_packet_cbr * packet,const struct pt_config * config)56774fe6c29SRuslan Bukin int pt_tcal_update_cbr(struct pt_time_cal *tcal,
56874fe6c29SRuslan Bukin 		      const struct pt_packet_cbr *packet,
56974fe6c29SRuslan Bukin 		      const struct pt_config *config)
57074fe6c29SRuslan Bukin {
57174fe6c29SRuslan Bukin 	/* A CBR outside of PSB+ indicates a frequency change.  Reset our
57274fe6c29SRuslan Bukin 	 * calibration state.
57374fe6c29SRuslan Bukin 	 */
57474fe6c29SRuslan Bukin 	pt_tcal_init(tcal);
57574fe6c29SRuslan Bukin 
57674fe6c29SRuslan Bukin 	return pt_tcal_header_cbr(tcal, packet, config);
57774fe6c29SRuslan Bukin }
57874fe6c29SRuslan Bukin 
pt_tcal_header_cbr(struct pt_time_cal * tcal,const struct pt_packet_cbr * packet,const struct pt_config * config)57974fe6c29SRuslan Bukin int pt_tcal_header_cbr(struct pt_time_cal *tcal,
58074fe6c29SRuslan Bukin 		      const struct pt_packet_cbr *packet,
58174fe6c29SRuslan Bukin 		      const struct pt_config *config)
58274fe6c29SRuslan Bukin {
58374fe6c29SRuslan Bukin 	uint64_t cbr, p1, fcr;
58474fe6c29SRuslan Bukin 
58574fe6c29SRuslan Bukin 	if (!tcal || !packet || !config)
58674fe6c29SRuslan Bukin 		return -pte_internal;
58774fe6c29SRuslan Bukin 
58874fe6c29SRuslan Bukin 	p1 = config->nom_freq;
58974fe6c29SRuslan Bukin 	if (!p1)
59074fe6c29SRuslan Bukin 		return 0;
59174fe6c29SRuslan Bukin 
59274fe6c29SRuslan Bukin 	/* If we know the nominal frequency, we can use it for calibration. */
59374fe6c29SRuslan Bukin 	cbr = packet->ratio;
594*85f87cf4SRuslan Bukin 	if (!cbr)
595*85f87cf4SRuslan Bukin 		return -pte_bad_packet;
59674fe6c29SRuslan Bukin 
59774fe6c29SRuslan Bukin 	fcr = (p1 << pt_tcal_fcr_shr) / cbr;
59874fe6c29SRuslan Bukin 
59974fe6c29SRuslan Bukin 	return pt_tcal_set_fcr(tcal, fcr);
60074fe6c29SRuslan Bukin }
60174fe6c29SRuslan Bukin 
pt_tcal_update_tma(struct pt_time_cal * tcal,const struct pt_packet_tma * packet,const struct pt_config * config)60274fe6c29SRuslan Bukin int pt_tcal_update_tma(struct pt_time_cal *tcal,
60374fe6c29SRuslan Bukin 		      const struct pt_packet_tma *packet,
60474fe6c29SRuslan Bukin 		      const struct pt_config *config)
60574fe6c29SRuslan Bukin {
60674fe6c29SRuslan Bukin 	(void) tcal;
60774fe6c29SRuslan Bukin 	(void) packet;
60874fe6c29SRuslan Bukin 	(void) config;
60974fe6c29SRuslan Bukin 
61074fe6c29SRuslan Bukin 	/* Nothing to do. */
61174fe6c29SRuslan Bukin 	return 0;
61274fe6c29SRuslan Bukin }
61374fe6c29SRuslan Bukin 
pt_tcal_update_mtc(struct pt_time_cal * tcal,const struct pt_packet_mtc * packet,const struct pt_config * config)61474fe6c29SRuslan Bukin int pt_tcal_update_mtc(struct pt_time_cal *tcal,
61574fe6c29SRuslan Bukin 		      const struct pt_packet_mtc *packet,
61674fe6c29SRuslan Bukin 		      const struct pt_config *config)
61774fe6c29SRuslan Bukin {
618*85f87cf4SRuslan Bukin 	uint32_t last_ctc, ctc, ctc_delta, have_mtc, check_skl168;
61974fe6c29SRuslan Bukin 	uint64_t cyc, fc, fcr;
62074fe6c29SRuslan Bukin 	int errcode;
62174fe6c29SRuslan Bukin 
62274fe6c29SRuslan Bukin 	if (!tcal || !packet || !config)
62374fe6c29SRuslan Bukin 		return -pte_internal;
62474fe6c29SRuslan Bukin 
62574fe6c29SRuslan Bukin 	last_ctc = tcal->ctc;
62674fe6c29SRuslan Bukin 	have_mtc = tcal->have_mtc;
62774fe6c29SRuslan Bukin 	cyc = tcal->cyc_mtc;
628*85f87cf4SRuslan Bukin 	check_skl168 = tcal->check_skl168;
62974fe6c29SRuslan Bukin 
630*85f87cf4SRuslan Bukin 	/* This only affects the first MTC after PSB. */
631*85f87cf4SRuslan Bukin 	tcal->check_skl168 = 0;
632*85f87cf4SRuslan Bukin 
633*85f87cf4SRuslan Bukin 	ctc = (uint32_t) packet->ctc << config->mtc_freq;
63474fe6c29SRuslan Bukin 
63574fe6c29SRuslan Bukin 	/* We need at least two MTC (including this). */
63674fe6c29SRuslan Bukin 	if (!have_mtc) {
63774fe6c29SRuslan Bukin 		tcal->cyc_mtc = 0ull;
63874fe6c29SRuslan Bukin 		tcal->ctc = ctc;
63974fe6c29SRuslan Bukin 		tcal->have_mtc = 1;
64074fe6c29SRuslan Bukin 
64174fe6c29SRuslan Bukin 		return 0;
64274fe6c29SRuslan Bukin 	}
64374fe6c29SRuslan Bukin 
64474fe6c29SRuslan Bukin 	/* Without any cycles, we can't calibrate.  Try again at the next
64574fe6c29SRuslan Bukin 	 * MTC and distribute the cycles over the combined MTC period.
64674fe6c29SRuslan Bukin 	 */
64774fe6c29SRuslan Bukin 	if (!cyc)
64874fe6c29SRuslan Bukin 		return 0;
64974fe6c29SRuslan Bukin 
65074fe6c29SRuslan Bukin 	/* Prepare for the next packet in case we error out below. */
65174fe6c29SRuslan Bukin 	tcal->have_mtc = 1;
65274fe6c29SRuslan Bukin 	tcal->cyc_mtc = 0ull;
65374fe6c29SRuslan Bukin 	tcal->ctc = ctc;
65474fe6c29SRuslan Bukin 
65574fe6c29SRuslan Bukin 	/* Let's pretend we will fail.  We'll correct it at the end. */
65674fe6c29SRuslan Bukin 	tcal->lost_mtc += 1;
65774fe6c29SRuslan Bukin 
65874fe6c29SRuslan Bukin 	errcode = pt_time_ctc_delta(&ctc_delta, ctc, last_ctc, config);
65974fe6c29SRuslan Bukin 	if (errcode < 0)
66074fe6c29SRuslan Bukin 		return errcode;
66174fe6c29SRuslan Bukin 
66274fe6c29SRuslan Bukin 	errcode = pt_time_ctc_fc(&fc, ctc_delta, config);
66374fe6c29SRuslan Bukin 	if (errcode < 0)
66474fe6c29SRuslan Bukin 		return errcode;
66574fe6c29SRuslan Bukin 
66674fe6c29SRuslan Bukin 	/* We shift the nominator to improve rounding precision.
66774fe6c29SRuslan Bukin 	 *
66874fe6c29SRuslan Bukin 	 * Since we're only collecting the CYCs between two MTC, we shouldn't
66974fe6c29SRuslan Bukin 	 * overflow.  Let's rather fail than overflow.
67074fe6c29SRuslan Bukin 	 */
67174fe6c29SRuslan Bukin 	if (fc & ~(~0ull >> pt_tcal_fcr_shr))
67274fe6c29SRuslan Bukin 		return -pte_internal;
67374fe6c29SRuslan Bukin 
67474fe6c29SRuslan Bukin 	fcr = (fc << pt_tcal_fcr_shr) / cyc;
67574fe6c29SRuslan Bukin 
676*85f87cf4SRuslan Bukin 	/* SKL168: Intel(R) PT CYC Packets Can be Dropped When Immediately
677*85f87cf4SRuslan Bukin 	 * Preceding PSB.
678*85f87cf4SRuslan Bukin 	 *
679*85f87cf4SRuslan Bukin 	 * We skip this MTC if we lost one or more MTC since the last PSB or if
680*85f87cf4SRuslan Bukin 	 * it looks like we lost a wrap CYC packet.
681*85f87cf4SRuslan Bukin 	 *
682*85f87cf4SRuslan Bukin 	 * This is not an error but we count that MTC as lost.
683*85f87cf4SRuslan Bukin 	 */
684*85f87cf4SRuslan Bukin 	if (check_skl168) {
685*85f87cf4SRuslan Bukin 		/* If we lost one or more MTC, the case is clear. */
686*85f87cf4SRuslan Bukin 		if ((1u << config->mtc_freq) < ctc_delta)
687*85f87cf4SRuslan Bukin 			return 0;
688*85f87cf4SRuslan Bukin 
689*85f87cf4SRuslan Bukin 		/* The case is less clear for a lost wrap CYC packet since we do
690*85f87cf4SRuslan Bukin 		 * have some variation in the number of cycles.
691*85f87cf4SRuslan Bukin 		 *
692*85f87cf4SRuslan Bukin 		 * The CYC counter wraps on the affected processors every 4096
693*85f87cf4SRuslan Bukin 		 * cycles.  For low MTC frequencies (high values), losing one
694*85f87cf4SRuslan Bukin 		 * may not be noticeable.
695*85f87cf4SRuslan Bukin 		 *
696*85f87cf4SRuslan Bukin 		 * We restrict the workaround to higher MTC frequencies (lower
697*85f87cf4SRuslan Bukin 		 * values).
698*85f87cf4SRuslan Bukin 		 *
699*85f87cf4SRuslan Bukin 		 * We also need a previous FCR so we know how many cycles to
700*85f87cf4SRuslan Bukin 		 * expect.
701*85f87cf4SRuslan Bukin 		 */
702*85f87cf4SRuslan Bukin 		if ((config->mtc_freq < 10) && pt_tcal_have_fcr(tcal)) {
703*85f87cf4SRuslan Bukin 			uint64_t dfc;
704*85f87cf4SRuslan Bukin 
705*85f87cf4SRuslan Bukin 			/* We choose a slightly lower adjustment to account for
706*85f87cf4SRuslan Bukin 			 * some normal variation.
707*85f87cf4SRuslan Bukin 			 */
708*85f87cf4SRuslan Bukin 			dfc = (tcal->fcr * (cyc + 0xf00)) >> pt_tcal_fcr_shr;
709*85f87cf4SRuslan Bukin 
710*85f87cf4SRuslan Bukin 			/* If we didn't drop a wrap CYC, @dfc should be way
711*85f87cf4SRuslan Bukin 			 * bigger than @fc.  If it isn't, we assume that the
712*85f87cf4SRuslan Bukin 			 * erratum applied.
713*85f87cf4SRuslan Bukin 			 */
714*85f87cf4SRuslan Bukin 			if (dfc < fc)
715*85f87cf4SRuslan Bukin 				return 0;
716*85f87cf4SRuslan Bukin 		}
717*85f87cf4SRuslan Bukin 	}
718*85f87cf4SRuslan Bukin 
71974fe6c29SRuslan Bukin 	errcode = pt_tcal_set_fcr(tcal, fcr);
72074fe6c29SRuslan Bukin 	if (errcode < 0)
72174fe6c29SRuslan Bukin 		return errcode;
72274fe6c29SRuslan Bukin 
72374fe6c29SRuslan Bukin 	/* We updated the FCR.  This recovers from previous MTC losses. */
72474fe6c29SRuslan Bukin 	tcal->lost_mtc = 0;
72574fe6c29SRuslan Bukin 
72674fe6c29SRuslan Bukin 	return 0;
72774fe6c29SRuslan Bukin }
72874fe6c29SRuslan Bukin 
pt_tcal_update_cyc(struct pt_time_cal * tcal,const struct pt_packet_cyc * packet,const struct pt_config * config)72974fe6c29SRuslan Bukin int pt_tcal_update_cyc(struct pt_time_cal *tcal,
73074fe6c29SRuslan Bukin 		      const struct pt_packet_cyc *packet,
73174fe6c29SRuslan Bukin 		      const struct pt_config *config)
73274fe6c29SRuslan Bukin {
73374fe6c29SRuslan Bukin 	uint64_t cyc;
73474fe6c29SRuslan Bukin 
73574fe6c29SRuslan Bukin 	(void) config;
73674fe6c29SRuslan Bukin 
73774fe6c29SRuslan Bukin 	if (!tcal || !packet)
73874fe6c29SRuslan Bukin 		return -pte_internal;
73974fe6c29SRuslan Bukin 
74074fe6c29SRuslan Bukin 	cyc = packet->value;
74174fe6c29SRuslan Bukin 	tcal->cyc_mtc += cyc;
74274fe6c29SRuslan Bukin 	tcal->cyc_tsc += cyc;
74374fe6c29SRuslan Bukin 
74474fe6c29SRuslan Bukin 	return 0;
74574fe6c29SRuslan Bukin }
746*85f87cf4SRuslan Bukin 
pt_tcal_update_ovf(struct pt_time_cal * tcal,const struct pt_config * config)747*85f87cf4SRuslan Bukin int pt_tcal_update_ovf(struct pt_time_cal *tcal,
748*85f87cf4SRuslan Bukin 		       const struct pt_config *config)
749*85f87cf4SRuslan Bukin {
750*85f87cf4SRuslan Bukin 	if (!tcal || !config)
751*85f87cf4SRuslan Bukin 		return -pte_internal;
752*85f87cf4SRuslan Bukin 
753*85f87cf4SRuslan Bukin 	tcal->tsc = 0ull;
754*85f87cf4SRuslan Bukin 	tcal->cyc_tsc = 0ull;
755*85f87cf4SRuslan Bukin 	tcal->cyc_mtc = 0ull;
756*85f87cf4SRuslan Bukin 	tcal->ctc = 0;
757*85f87cf4SRuslan Bukin 	tcal->have_mtc = 0;
758*85f87cf4SRuslan Bukin 
759*85f87cf4SRuslan Bukin 	return 0;
760*85f87cf4SRuslan Bukin }
761