162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PTP 1588 clock support - support for timestamping in PHY devices
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010 OMICRON electronics GmbH
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/errqueue.h>
862306a36Sopenharmony_ci#include <linux/phy.h>
962306a36Sopenharmony_ci#include <linux/ptp_classify.h>
1062306a36Sopenharmony_ci#include <linux/skbuff.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic unsigned int classify(const struct sk_buff *skb)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	if (likely(skb->dev && skb->dev->phydev &&
1662306a36Sopenharmony_ci		   skb->dev->phydev->mii_ts))
1762306a36Sopenharmony_ci		return ptp_classify_raw(skb);
1862306a36Sopenharmony_ci	else
1962306a36Sopenharmony_ci		return PTP_CLASS_NONE;
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_civoid skb_clone_tx_timestamp(struct sk_buff *skb)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct mii_timestamper *mii_ts;
2562306a36Sopenharmony_ci	struct sk_buff *clone;
2662306a36Sopenharmony_ci	unsigned int type;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (!skb->sk)
2962306a36Sopenharmony_ci		return;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	type = classify(skb);
3262306a36Sopenharmony_ci	if (type == PTP_CLASS_NONE)
3362306a36Sopenharmony_ci		return;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	mii_ts = skb->dev->phydev->mii_ts;
3662306a36Sopenharmony_ci	if (likely(mii_ts->txtstamp)) {
3762306a36Sopenharmony_ci		clone = skb_clone_sk(skb);
3862306a36Sopenharmony_ci		if (!clone)
3962306a36Sopenharmony_ci			return;
4062306a36Sopenharmony_ci		mii_ts->txtstamp(mii_ts, clone, type);
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cibool skb_defer_rx_timestamp(struct sk_buff *skb)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct mii_timestamper *mii_ts;
4862306a36Sopenharmony_ci	unsigned int type;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->mii_ts)
5162306a36Sopenharmony_ci		return false;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (skb_headroom(skb) < ETH_HLEN)
5462306a36Sopenharmony_ci		return false;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	__skb_push(skb, ETH_HLEN);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	type = ptp_classify_raw(skb);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	__skb_pull(skb, ETH_HLEN);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (type == PTP_CLASS_NONE)
6362306a36Sopenharmony_ci		return false;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	mii_ts = skb->dev->phydev->mii_ts;
6662306a36Sopenharmony_ci	if (likely(mii_ts->rxtstamp))
6762306a36Sopenharmony_ci		return mii_ts->rxtstamp(mii_ts, skb, type);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return false;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);
72