diff --git a/Documentation/ABI/testing/sysfs-class-net-timestamping b/Documentation/ABI/testing/sysfs-class-net-timestamping
new file mode 100644
index 000000000000..529c3a6eb607
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-net-timestamping
@@ -0,0 +1,17 @@
+What:		/sys/class/net/<iface>/available_timestamping_providers
+Date:		January 2022
+Contact:	Richard Cochran <richardcochran@gmail.com>
+Description:
+		Enumerates the available providers for SO_TIMESTAMPING.
+		The possible values are:
+		- "mac"  The MAC provides time stamping.
+		- "phy"  The PHY or MII device provides time stamping.
+
+What:		/sys/class/net/<iface>/current_timestamping_provider
+Date:		January 2022
+Contact:	Richard Cochran <richardcochran@gmail.com>
+Description:
+		Show the current SO_TIMESTAMPING provider.
+		The possible values are:
+		- "mac"  The MAC provides time stamping.
+		- "phy"  The PHY or MII device provides time stamping.
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 74d8e1dc125f..5538ee27e865 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1415,6 +1415,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 
 	phydev->phy_link_change = phy_link_change;
 	if (dev) {
+		dev->selected_timestamping_layer = PHY_TIMESTAMPING;
 		phydev->attached_dev = dev;
 		dev->phydev = phydev;
 
@@ -1727,6 +1728,7 @@ void phy_detach(struct phy_device *phydev)
 
 	phy_suspend(phydev);
 	if (dev) {
+		dev->selected_timestamping_layer = MAC_TIMESTAMPING;
 		phydev->attached_dev->phydev = NULL;
 		phydev->attached_dev = NULL;
 	}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2684bdb6defa..b44ae00df3a8 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1687,6 +1687,11 @@ enum netdev_ml_priv_type {
 	ML_PRIV_CAN,
 };
 
+enum timestamping_layer {
+	MAC_TIMESTAMPING,
+	PHY_TIMESTAMPING,
+};
+
 /**
  *	struct net_device - The DEVICE structure.
  *
@@ -1927,6 +1932,9 @@ enum netdev_ml_priv_type {
  *
  *	@threaded:	napi threaded mode is enabled
  *
+ *	@selected_timestamping_layer:	Tracks whether the MAC or the PHY
+ *					performs packet time stamping.
+ *
  *	@net_notifier_list:	List of per-net netdev notifier block
  *				that follow this device when it is moved
  *				to another network namespace.
@@ -2263,6 +2271,8 @@ struct net_device {
 	unsigned		wol_enabled:1;
 	unsigned		threaded:1;
 
+	enum timestamping_layer selected_timestamping_layer;
+
 	struct list_head	net_notifier_list;
 
 #if IS_ENABLED(CONFIG_MACSEC)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 53ea262ecafd..4ff7ef417c38 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -618,6 +618,64 @@ static ssize_t threaded_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(threaded);
 
+static ssize_t available_timestamping_providers_show(struct device *dev,
+						     struct device_attribute *attr,
+						     char *buf)
+{
+	const struct ethtool_ops *ops;
+	struct net_device *netdev;
+	struct phy_device *phydev;
+	int ret = 0;
+
+	netdev = to_net_dev(dev);
+	phydev = netdev->phydev;
+	ops = netdev->ethtool_ops;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	ret += sprintf(buf, "%s\n", "mac");
+	buf += 4;
+
+	if (phy_has_tsinfo(phydev)) {
+		ret += sprintf(buf, "%s\n", "phy");
+		buf += 4;
+	}
+
+	rtnl_unlock();
+
+	return ret;
+}
+static DEVICE_ATTR_RO(available_timestamping_providers);
+
+static ssize_t current_timestamping_provider_show(struct device *dev,
+						  struct device_attribute *attr,
+						  char *buf)
+{
+	const struct ethtool_ops *ops;
+	struct net_device *netdev;
+	struct phy_device *phydev;
+	int ret;
+
+	netdev = to_net_dev(dev);
+	phydev = netdev->phydev;
+	ops = netdev->ethtool_ops;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	if (phy_has_tsinfo(phydev)) {
+		ret = sprintf(buf, "%s\n", "phy");
+	} else {
+		ret = sprintf(buf, "%s\n", "mac");
+	}
+
+	rtnl_unlock();
+
+	return ret;
+}
+static DEVICE_ATTR_RO(current_timestamping_provider);
+
 static struct attribute *net_class_attrs[] __ro_after_init = {
 	&dev_attr_netdev_group.attr,
 	&dev_attr_type.attr,
@@ -651,6 +709,8 @@ static struct attribute *net_class_attrs[] __ro_after_init = {
 	&dev_attr_carrier_up_count.attr,
 	&dev_attr_carrier_down_count.attr,
 	&dev_attr_threaded.attr,
+	&dev_attr_available_timestamping_providers.attr,
+	&dev_attr_current_timestamping_provider.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(net_class);
