drivers/net/ethernet/mellanox/mlx4/en_clock.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx4/en_clock.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx4/en_clock.c
Extension
.c
Size
9054 bytes
Lines
302
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

#include <linux/mlx4/device.h>
#include <linux/clocksource.h>

#include "mlx4_en.h"

/* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
 */
static u64 mlx4_en_read_clock(struct cyclecounter *tc)
{
	struct mlx4_en_dev *mdev =
		container_of(tc, struct mlx4_en_dev, cycles);
	struct mlx4_dev *dev = mdev->dev;

	return mlx4_read_clock(dev) & tc->mask;
}

u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
{
	u64 hi, lo;
	struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;

	lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo);
	hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16;

	return hi | lo;
}

u64 mlx4_en_get_hwtstamp(struct mlx4_en_dev *mdev, u64 timestamp)
{
	unsigned int seq;
	u64 nsec;

	do {
		seq = read_seqbegin(&mdev->clock_lock);
		nsec = timecounter_cyc2time(&mdev->clock, timestamp);
	} while (read_seqretry(&mdev->clock_lock, seq));

	return ns_to_ktime(nsec);
}

void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
			    struct skb_shared_hwtstamps *hwts,
			    u64 timestamp)
{
	memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
	hwts->hwtstamp = mlx4_en_get_hwtstamp(mdev, timestamp);
}

/**
 * mlx4_en_remove_timestamp - disable PTP device
 * @mdev: board private structure
 *
 * Stop the PTP support.
 **/
void mlx4_en_remove_timestamp(struct mlx4_en_dev *mdev)
{
	if (mdev->ptp_clock) {
		ptp_clock_unregister(mdev->ptp_clock);
		mdev->ptp_clock = NULL;
		mlx4_info(mdev, "removed PHC\n");
	}
}

#define MLX4_EN_WRAP_AROUND_SEC	10UL
/* By scheduling the overflow check every 5 seconds, we have a reasonably
 * good chance we won't miss a wrap around.
 * TODO: Use a timer instead of a work queue to increase the guarantee.
 */
#define MLX4_EN_OVERFLOW_PERIOD (MLX4_EN_WRAP_AROUND_SEC * HZ / 2)

void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
{
	bool timeout = time_is_before_jiffies(mdev->last_overflow_check +
					      MLX4_EN_OVERFLOW_PERIOD);
	unsigned long flags;

	if (timeout) {
		write_seqlock_irqsave(&mdev->clock_lock, flags);
		timecounter_read(&mdev->clock);
		write_sequnlock_irqrestore(&mdev->clock_lock, flags);
		mdev->last_overflow_check = jiffies;
	}
}

/**
 * mlx4_en_phc_adjfine - adjust the frequency of the hardware clock
 * @ptp: ptp clock structure
 * @scaled_ppm: Desired frequency change in scaled parts per million
 *
 * Adjust the frequency of the PHC cycle counter by the indicated scaled_ppm

Annotation

Implementation Notes