162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/mlx4/device.h>
3562306a36Sopenharmony_ci#include <linux/clocksource.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include "mlx4_en.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistatic u64 mlx4_en_read_clock(const struct cyclecounter *tc)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct mlx4_en_dev *mdev =
4462306a36Sopenharmony_ci		container_of(tc, struct mlx4_en_dev, cycles);
4562306a36Sopenharmony_ci	struct mlx4_dev *dev = mdev->dev;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return mlx4_read_clock(dev) & tc->mask;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciu64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	u64 hi, lo;
5362306a36Sopenharmony_ci	struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo);
5662306a36Sopenharmony_ci	hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return hi | lo;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciu64 mlx4_en_get_hwtstamp(struct mlx4_en_dev *mdev, u64 timestamp)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	unsigned int seq;
6462306a36Sopenharmony_ci	u64 nsec;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	do {
6762306a36Sopenharmony_ci		seq = read_seqbegin(&mdev->clock_lock);
6862306a36Sopenharmony_ci		nsec = timecounter_cyc2time(&mdev->clock, timestamp);
6962306a36Sopenharmony_ci	} while (read_seqretry(&mdev->clock_lock, seq));
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return ns_to_ktime(nsec);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_civoid mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
7562306a36Sopenharmony_ci			    struct skb_shared_hwtstamps *hwts,
7662306a36Sopenharmony_ci			    u64 timestamp)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
7962306a36Sopenharmony_ci	hwts->hwtstamp = mlx4_en_get_hwtstamp(mdev, timestamp);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/**
8362306a36Sopenharmony_ci * mlx4_en_remove_timestamp - disable PTP device
8462306a36Sopenharmony_ci * @mdev: board private structure
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * Stop the PTP support.
8762306a36Sopenharmony_ci **/
8862306a36Sopenharmony_civoid mlx4_en_remove_timestamp(struct mlx4_en_dev *mdev)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (mdev->ptp_clock) {
9162306a36Sopenharmony_ci		ptp_clock_unregister(mdev->ptp_clock);
9262306a36Sopenharmony_ci		mdev->ptp_clock = NULL;
9362306a36Sopenharmony_ci		mlx4_info(mdev, "removed PHC\n");
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define MLX4_EN_WRAP_AROUND_SEC	10UL
9862306a36Sopenharmony_ci/* By scheduling the overflow check every 5 seconds, we have a reasonably
9962306a36Sopenharmony_ci * good chance we wont miss a wrap around.
10062306a36Sopenharmony_ci * TOTO: Use a timer instead of a work queue to increase the guarantee.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci#define MLX4_EN_OVERFLOW_PERIOD (MLX4_EN_WRAP_AROUND_SEC * HZ / 2)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_civoid mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	bool timeout = time_is_before_jiffies(mdev->last_overflow_check +
10762306a36Sopenharmony_ci					      MLX4_EN_OVERFLOW_PERIOD);
10862306a36Sopenharmony_ci	unsigned long flags;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (timeout) {
11162306a36Sopenharmony_ci		write_seqlock_irqsave(&mdev->clock_lock, flags);
11262306a36Sopenharmony_ci		timecounter_read(&mdev->clock);
11362306a36Sopenharmony_ci		write_sequnlock_irqrestore(&mdev->clock_lock, flags);
11462306a36Sopenharmony_ci		mdev->last_overflow_check = jiffies;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * mlx4_en_phc_adjfine - adjust the frequency of the hardware clock
12062306a36Sopenharmony_ci * @ptp: ptp clock structure
12162306a36Sopenharmony_ci * @scaled_ppm: Desired frequency change in scaled parts per million
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * Adjust the frequency of the PHC cycle counter by the indicated scaled_ppm
12462306a36Sopenharmony_ci * from the base frequency.
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * Scaled parts per million is ppm with a 16-bit binary fractional field.
12762306a36Sopenharmony_ci **/
12862306a36Sopenharmony_cistatic int mlx4_en_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	u32 mult;
13162306a36Sopenharmony_ci	unsigned long flags;
13262306a36Sopenharmony_ci	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
13362306a36Sopenharmony_ci						ptp_clock_info);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	mult = (u32)adjust_by_scaled_ppm(mdev->nominal_c_mult, scaled_ppm);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	write_seqlock_irqsave(&mdev->clock_lock, flags);
13862306a36Sopenharmony_ci	timecounter_read(&mdev->clock);
13962306a36Sopenharmony_ci	mdev->cycles.mult = mult;
14062306a36Sopenharmony_ci	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/**
14662306a36Sopenharmony_ci * mlx4_en_phc_adjtime - Shift the time of the hardware clock
14762306a36Sopenharmony_ci * @ptp: ptp clock structure
14862306a36Sopenharmony_ci * @delta: Desired change in nanoseconds
14962306a36Sopenharmony_ci *
15062306a36Sopenharmony_ci * Adjust the timer by resetting the timecounter structure.
15162306a36Sopenharmony_ci **/
15262306a36Sopenharmony_cistatic int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
15562306a36Sopenharmony_ci						ptp_clock_info);
15662306a36Sopenharmony_ci	unsigned long flags;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	write_seqlock_irqsave(&mdev->clock_lock, flags);
15962306a36Sopenharmony_ci	timecounter_adjtime(&mdev->clock, delta);
16062306a36Sopenharmony_ci	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/**
16662306a36Sopenharmony_ci * mlx4_en_phc_gettime - Reads the current time from the hardware clock
16762306a36Sopenharmony_ci * @ptp: ptp clock structure
16862306a36Sopenharmony_ci * @ts: timespec structure to hold the current time value
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * Read the timecounter and return the correct value in ns after converting
17162306a36Sopenharmony_ci * it into a struct timespec.
17262306a36Sopenharmony_ci **/
17362306a36Sopenharmony_cistatic int mlx4_en_phc_gettime(struct ptp_clock_info *ptp,
17462306a36Sopenharmony_ci			       struct timespec64 *ts)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
17762306a36Sopenharmony_ci						ptp_clock_info);
17862306a36Sopenharmony_ci	unsigned long flags;
17962306a36Sopenharmony_ci	u64 ns;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	write_seqlock_irqsave(&mdev->clock_lock, flags);
18262306a36Sopenharmony_ci	ns = timecounter_read(&mdev->clock);
18362306a36Sopenharmony_ci	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	*ts = ns_to_timespec64(ns);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return 0;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/**
19162306a36Sopenharmony_ci * mlx4_en_phc_settime - Set the current time on the hardware clock
19262306a36Sopenharmony_ci * @ptp: ptp clock structure
19362306a36Sopenharmony_ci * @ts: timespec containing the new time for the cycle counter
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * Reset the timecounter to use a new base value instead of the kernel
19662306a36Sopenharmony_ci * wall timer value.
19762306a36Sopenharmony_ci **/
19862306a36Sopenharmony_cistatic int mlx4_en_phc_settime(struct ptp_clock_info *ptp,
19962306a36Sopenharmony_ci			       const struct timespec64 *ts)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
20262306a36Sopenharmony_ci						ptp_clock_info);
20362306a36Sopenharmony_ci	u64 ns = timespec64_to_ns(ts);
20462306a36Sopenharmony_ci	unsigned long flags;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* reset the timecounter */
20762306a36Sopenharmony_ci	write_seqlock_irqsave(&mdev->clock_lock, flags);
20862306a36Sopenharmony_ci	timecounter_init(&mdev->clock, &mdev->cycles, ns);
20962306a36Sopenharmony_ci	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * mlx4_en_phc_enable - enable or disable an ancillary feature
21662306a36Sopenharmony_ci * @ptp: ptp clock structure
21762306a36Sopenharmony_ci * @request: Desired resource to enable or disable
21862306a36Sopenharmony_ci * @on: Caller passes one to enable or zero to disable
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * Enable (or disable) ancillary features of the PHC subsystem.
22162306a36Sopenharmony_ci * Currently, no ancillary features are supported.
22262306a36Sopenharmony_ci **/
22362306a36Sopenharmony_cistatic int mlx4_en_phc_enable(struct ptp_clock_info __always_unused *ptp,
22462306a36Sopenharmony_ci			      struct ptp_clock_request __always_unused *request,
22562306a36Sopenharmony_ci			      int __always_unused on)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	return -EOPNOTSUPP;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic const struct ptp_clock_info mlx4_en_ptp_clock_info = {
23162306a36Sopenharmony_ci	.owner		= THIS_MODULE,
23262306a36Sopenharmony_ci	.max_adj	= 100000000,
23362306a36Sopenharmony_ci	.n_alarm	= 0,
23462306a36Sopenharmony_ci	.n_ext_ts	= 0,
23562306a36Sopenharmony_ci	.n_per_out	= 0,
23662306a36Sopenharmony_ci	.n_pins		= 0,
23762306a36Sopenharmony_ci	.pps		= 0,
23862306a36Sopenharmony_ci	.adjfine	= mlx4_en_phc_adjfine,
23962306a36Sopenharmony_ci	.adjtime	= mlx4_en_phc_adjtime,
24062306a36Sopenharmony_ci	.gettime64	= mlx4_en_phc_gettime,
24162306a36Sopenharmony_ci	.settime64	= mlx4_en_phc_settime,
24262306a36Sopenharmony_ci	.enable		= mlx4_en_phc_enable,
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/* This function calculates the max shift that enables the user range
24762306a36Sopenharmony_ci * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cistatic u32 freq_to_shift(u16 freq)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	u32 freq_khz = freq * 1000;
25262306a36Sopenharmony_ci	u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
25362306a36Sopenharmony_ci	u64 max_val_cycles_rounded = 1ULL << fls64(max_val_cycles - 1);
25462306a36Sopenharmony_ci	/* calculate max possible multiplier in order to fit in 64bit */
25562306a36Sopenharmony_ci	u64 max_mul = div64_u64(ULLONG_MAX, max_val_cycles_rounded);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* This comes from the reverse of clocksource_khz2mult */
25862306a36Sopenharmony_ci	return ilog2(div_u64(max_mul * freq_khz, 1000000));
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_civoid mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct mlx4_dev *dev = mdev->dev;
26462306a36Sopenharmony_ci	unsigned long flags;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* mlx4_en_init_timestamp is called for each netdev.
26762306a36Sopenharmony_ci	 * mdev->ptp_clock is common for all ports, skip initialization if
26862306a36Sopenharmony_ci	 * was done for other port.
26962306a36Sopenharmony_ci	 */
27062306a36Sopenharmony_ci	if (mdev->ptp_clock)
27162306a36Sopenharmony_ci		return;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	seqlock_init(&mdev->clock_lock);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	memset(&mdev->cycles, 0, sizeof(mdev->cycles));
27662306a36Sopenharmony_ci	mdev->cycles.read = mlx4_en_read_clock;
27762306a36Sopenharmony_ci	mdev->cycles.mask = CLOCKSOURCE_MASK(48);
27862306a36Sopenharmony_ci	mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);
27962306a36Sopenharmony_ci	mdev->cycles.mult =
28062306a36Sopenharmony_ci		clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
28162306a36Sopenharmony_ci	mdev->nominal_c_mult = mdev->cycles.mult;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	write_seqlock_irqsave(&mdev->clock_lock, flags);
28462306a36Sopenharmony_ci	timecounter_init(&mdev->clock, &mdev->cycles,
28562306a36Sopenharmony_ci			 ktime_to_ns(ktime_get_real()));
28662306a36Sopenharmony_ci	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Configure the PHC */
28962306a36Sopenharmony_ci	mdev->ptp_clock_info = mlx4_en_ptp_clock_info;
29062306a36Sopenharmony_ci	snprintf(mdev->ptp_clock_info.name, 16, "mlx4 ptp");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	mdev->ptp_clock = ptp_clock_register(&mdev->ptp_clock_info,
29362306a36Sopenharmony_ci					     &mdev->pdev->dev);
29462306a36Sopenharmony_ci	if (IS_ERR(mdev->ptp_clock)) {
29562306a36Sopenharmony_ci		mdev->ptp_clock = NULL;
29662306a36Sopenharmony_ci		mlx4_err(mdev, "ptp_clock_register failed\n");
29762306a36Sopenharmony_ci	} else if (mdev->ptp_clock) {
29862306a36Sopenharmony_ci		mlx4_info(mdev, "registered PHC clock\n");
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci}
302