diff mbox

[net-next,1/2] net: add support for Cavium PTP coprocessor

Message ID 20171107190704.15458-2-aleksey.makarov@cavium.com (mailing list archive)
State New, archived
Headers show

Commit Message

Aleksey Makarov Nov. 7, 2017, 7:07 p.m. UTC
From: Radoslaw Biernacki <rad@semihalf.com>

This patch adds support for the Precision Time Protocol
Clocks and Timestamping hardware found on Cavium ThunderX
processors.

Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
Signed-off-by: Aleksey Makarov <aleksey.makarov@cavium.com>
---
 drivers/net/ethernet/cavium/Kconfig             |  13 +
 drivers/net/ethernet/cavium/Makefile            |   1 +
 drivers/net/ethernet/cavium/common/Makefile     |   1 +
 drivers/net/ethernet/cavium/common/cavium_ptp.c | 353 ++++++++++++++++++++++++
 drivers/net/ethernet/cavium/common/cavium_ptp.h |  78 ++++++
 5 files changed, 446 insertions(+)
 create mode 100644 drivers/net/ethernet/cavium/common/Makefile
 create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.c
 create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.h

Comments

David Daney Nov. 7, 2017, 7:49 p.m. UTC | #1
On 11/07/2017 11:07 AM, Aleksey Makarov wrote:
> From: Radoslaw Biernacki <rad@semihalf.com>
> 
> This patch adds support for the Precision Time Protocol
> Clocks and Timestamping hardware found on Cavium ThunderX
> processors.
> 
> Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
> Signed-off-by: Aleksey Makarov <aleksey.makarov@cavium.com>
> ---
>   drivers/net/ethernet/cavium/Kconfig             |  13 +
>   drivers/net/ethernet/cavium/Makefile            |   1 +
>   drivers/net/ethernet/cavium/common/Makefile     |   1 +
>   drivers/net/ethernet/cavium/common/cavium_ptp.c | 353 ++++++++++++++++++++++++
>   drivers/net/ethernet/cavium/common/cavium_ptp.h |  78 ++++++
>   5 files changed, 446 insertions(+)
>   create mode 100644 drivers/net/ethernet/cavium/common/Makefile
>   create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.c
>   create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.h
> 
[...]
> +
> +/* The Cavium PTP can *only* be found in SoCs containing the ThunderX
> + * ARM64 CPU implementation.  All accesses to the device registers on this
> + * platform are implicitly strongly ordered with respect to memory
> + * accesses.

I believe that is not correct.  I/O register accesses are implicitly 
ordered with respect to other I/O register accesses.  However, with 
respect to memory accesses, no ordering is imposed.  Therefore, one must 
be very careful not to introduce subtile memory ordering bugs with these 
things when using the unordered versions.

> + * So writeq_relaxed() and readq_relaxed() are safe to use with
> + * no memory barriers in this driver.  The readq()/writeq() functions add
> + * explicit ordering operation which in this case are redundant, and only
> + * add overhead.


Also it should be noted that on production silicon, the performance 
difference between the "relaxed" variant and the normal variant of 
read*/write* is often negligible.


> + */
> +
> +static u64 cavium_ptp_reg_read(struct cavium_ptp *clock, u64 offset)
> +{
> +	return readq_relaxed(clock->reg_base + offset);
> +}
> +
> +static void cavium_ptp_reg_write(struct cavium_ptp *clock, u64 offset, u64 val)
> +{
> +	writeq_relaxed(val, clock->reg_base + offset);
> +}
> +

Are the PTP register access really so much in the hot path that using 
the relaxed variants can be measured here?  If not, would it make the 
driver look cleaner to remove these and just use readq/writeq calls 
directly  in the body of the driver?

David.
Aleksey Makarov Nov. 8, 2017, 12:14 p.m. UTC | #2
On 11/07/2017 10:49 PM, David Daney wrote:
> On 11/07/2017 11:07 AM, Aleksey Makarov wrote:
>> From: Radoslaw Biernacki <rad@semihalf.com>
>>
>> This patch adds support for the Precision Time Protocol
>> Clocks and Timestamping hardware found on Cavium ThunderX
>> processors.
>>
>> Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
>> Signed-off-by: Aleksey Makarov <aleksey.makarov@cavium.com>
>> ---
>>   drivers/net/ethernet/cavium/Kconfig             |  13 +
>>   drivers/net/ethernet/cavium/Makefile            |   1 +
>>   drivers/net/ethernet/cavium/common/Makefile     |   1 +
>>   drivers/net/ethernet/cavium/common/cavium_ptp.c | 353 ++++++++++++++++++++++++
>>   drivers/net/ethernet/cavium/common/cavium_ptp.h |  78 ++++++
>>   5 files changed, 446 insertions(+)
>>   create mode 100644 drivers/net/ethernet/cavium/common/Makefile
>>   create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.c
>>   create mode 100644 drivers/net/ethernet/cavium/common/cavium_ptp.h
>>
> [...]
>> +
>> +/* The Cavium PTP can *only* be found in SoCs containing the ThunderX
>> + * ARM64 CPU implementation.  All accesses to the device registers on this
>> + * platform are implicitly strongly ordered with respect to memory
>> + * accesses.
> 
> I believe that is not correct.  I/O register accesses are implicitly
> ordered with respect to other I/O register accesses.  However, with
> respect to memory accesses, no ordering is imposed.  Therefore, one
> must be very careful not to introduce subtile memory ordering bugs
> with these things when using the unordered versions.

I will fix it in the next version.

Thank you
Aleksey Makarov

>> + * So writeq_relaxed() and readq_relaxed() are safe to use with
>> + * no memory barriers in this driver.  The readq()/writeq() functions add
>> + * explicit ordering operation which in this case are redundant, and only
>> + * add overhead.
> 
> 
> Also it should be noted that on production silicon, the performance difference between the "relaxed" variant and the normal variant of read*/write* is often negligible.
> 
> 
>> + */
>> +
>> +static u64 cavium_ptp_reg_read(struct cavium_ptp *clock, u64 offset)
>> +{
>> +    return readq_relaxed(clock->reg_base + offset);
>> +}
>> +
>> +static void cavium_ptp_reg_write(struct cavium_ptp *clock, u64 offset, u64 val)
>> +{
>> +    writeq_relaxed(val, clock->reg_base + offset);
>> +}
>> +
> 
> Are the PTP register access really so much in the hot path that using the relaxed variants can be measured here?  If not, would it make the driver look cleaner to remove these and just use readq/writeq calls directly  in the body of the driver?
> 
> David.
diff mbox

Patch

diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig
index dcbce6cac63e..634c79a8c812 100644
--- a/drivers/net/ethernet/cavium/Kconfig
+++ b/drivers/net/ethernet/cavium/Kconfig
@@ -50,6 +50,19 @@  config	THUNDER_NIC_RGX
 	  This driver supports configuring XCV block of RGX interface
 	  present on CN81XX chip.
 
+config CAVIUM_PTP
+	tristate "Cavium PTP coprocessor as PTP clock"
+	depends on 64BIT
+	depends on PTP_1588_CLOCK
+	select CAVIUM_RST
+	default y
+	---help---
+	  This driver adds support for the Precision Time Protocol Clocks and
+	  Timestamping coprocessor (PTP) found on Cavium processors.
+	  PTP provides timestamping mechanism that is suitable for use in IEEE 1588
+	  Precision Time Protocol or other purposes.  Timestamps can be used in
+	  BGX, TNS, GTI, and NIC blocks.
+
 config LIQUIDIO
 	tristate "Cavium LiquidIO support"
 	depends on 64BIT
diff --git a/drivers/net/ethernet/cavium/Makefile b/drivers/net/ethernet/cavium/Makefile
index 872da9f7c31a..946bba84e81d 100644
--- a/drivers/net/ethernet/cavium/Makefile
+++ b/drivers/net/ethernet/cavium/Makefile
@@ -1,6 +1,7 @@ 
 #
 # Makefile for the Cavium ethernet device drivers.
 #
+obj-$(CONFIG_NET_VENDOR_CAVIUM) += common/
 obj-$(CONFIG_NET_VENDOR_CAVIUM) += thunder/
 obj-$(CONFIG_NET_VENDOR_CAVIUM) += liquidio/
 obj-$(CONFIG_NET_VENDOR_CAVIUM) += octeon/
diff --git a/drivers/net/ethernet/cavium/common/Makefile b/drivers/net/ethernet/cavium/common/Makefile
new file mode 100644
index 000000000000..dd8561b8060b
--- /dev/null
+++ b/drivers/net/ethernet/cavium/common/Makefile
@@ -0,0 +1 @@ 
+obj-$(CONFIG_CAVIUM_PTP) += cavium_ptp.o
diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.c b/drivers/net/ethernet/cavium/common/cavium_ptp.c
new file mode 100644
index 000000000000..6c6f162bedbf
--- /dev/null
+++ b/drivers/net/ethernet/cavium/common/cavium_ptp.c
@@ -0,0 +1,353 @@ 
+/*
+ * cavium_ptp.c - PTP 1588 clock on Cavium hardware
+ *
+ * Copyright (c) 2003-2015, 2017 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/timecounter.h>
+#include <linux/pci.h>
+
+#include "cavium_ptp.h"
+
+#define DRV_NAME	"Cavium PTP Driver"
+
+#define PCI_DEVICE_ID_CAVIUM_PTP	0xA00C
+#define PCI_DEVICE_ID_CAVIUM_RST	0xA00E
+
+#define PCI_PTP_BAR_NO	0
+#define PCI_RST_BAR_NO	0
+
+#define PTP_CLOCK_CFG		0xF00ULL
+#define  PTP_CLOCK_CFG_PTP_EN	BIT(0)
+#define PTP_CLOCK_LO		0xF08ULL
+#define PTP_CLOCK_HI		0xF10ULL
+#define PTP_CLOCK_COMP		0xF18ULL
+
+#define RST_BOOT	0x1600ULL
+#define CLOCK_BASE_RATE	50000000ULL
+
+static u64 ptp_cavium_clock_get(void)
+{
+	struct pci_dev *pdev;
+	void __iomem *base;
+	u64 ret = CLOCK_BASE_RATE * 16;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
+			      PCI_DEVICE_ID_CAVIUM_RST, NULL);
+	if (!pdev)
+		goto error;
+
+	base = pci_ioremap_bar(pdev, PCI_RST_BAR_NO);
+	if (!base)
+		goto error_put_pdev;
+
+	ret = CLOCK_BASE_RATE * ((readq_relaxed(base + RST_BOOT) >> 33) & 0x3f);
+
+	iounmap(base);
+
+error_put_pdev:
+	pci_dev_put(pdev);
+
+error:
+	return ret;
+}
+
+/* The Cavium PTP can *only* be found in SoCs containing the ThunderX
+ * ARM64 CPU implementation.  All accesses to the device registers on this
+ * platform are implicitly strongly ordered with respect to memory
+ * accesses. So writeq_relaxed() and readq_relaxed() are safe to use with
+ * no memory barriers in this driver.  The readq()/writeq() functions add
+ * explicit ordering operation which in this case are redundant, and only
+ * add overhead.
+ */
+
+static u64 cavium_ptp_reg_read(struct cavium_ptp *clock, u64 offset)
+{
+	return readq_relaxed(clock->reg_base + offset);
+}
+
+static void cavium_ptp_reg_write(struct cavium_ptp *clock, u64 offset, u64 val)
+{
+	writeq_relaxed(val, clock->reg_base + offset);
+}
+
+struct cavium_ptp *cavium_ptp_get(void)
+{
+	struct cavium_ptp *ptp;
+	struct pci_dev *pdev;
+
+	pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
+			      PCI_DEVICE_ID_CAVIUM_PTP, NULL);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	ptp = pci_get_drvdata(pdev);
+	if (!ptp) {
+		pci_dev_put(pdev);
+		ptp = ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return ptp;
+}
+EXPORT_SYMBOL(cavium_ptp_get);
+
+void cavium_ptp_put(struct cavium_ptp *ptp)
+{
+	pci_dev_put(ptp->pdev);
+}
+EXPORT_SYMBOL(cavium_ptp_put);
+
+/**
+ * cavium_ptp_adjfreq() - Adjust ptp frequency
+ * @ptp: PTP clock info
+ * @ppb: how much to adjust by, in parts-per-billion
+ */
+static int cavium_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
+{
+	struct cavium_ptp *clock =
+		container_of(ptp_info, struct cavium_ptp, ptp_info);
+	unsigned long flags;
+	u64 comp;
+	u64 adj;
+	bool neg_adj = false;
+
+	if (ppb < 0) {
+		neg_adj = true;
+		ppb = -ppb;
+	}
+
+	/* The hardware adds the clock compensation value to the PTP clock
+	 * on every coprocessor clock cycle. Typical convention is that it
+	 * represent number of nanosecond betwen each cycle. In this
+	 * convention compensation value is in 64 bit fixed-point
+	 * representation where upper 32 bits are number of nanoseconds
+	 * and lower is fractions of nanosecond.
+	 * The ppb represent the ratio in "parts per bilion" by which the
+	 * compensation value should be corrected.
+	 * To calculate new compenstation value we use 64bit fixed point
+	 * arithmetic on following formula comp = tbase + tbase * ppb / 1G
+	 * where tbase is the basic compensation value calculated initialy
+	 * in cavium_ptp_init() -> tbase = 1/Hz. Then we use endian
+	 * independent structure definition to write data to PTP register.
+	 */
+	comp = ((u64)1000000000ull << 32) / clock->clock_rate;
+	adj = comp * ppb;
+	adj = div_u64(adj, 1000000000ull);
+	comp = neg_adj ? comp - adj : comp + adj;
+
+	spin_lock_irqsave(&clock->spin_lock, flags);
+	cavium_ptp_reg_write(clock, PTP_CLOCK_COMP, comp);
+	spin_unlock_irqrestore(&clock->spin_lock, flags);
+
+	return 0;
+}
+
+/**
+ * cavium_ptp_adjtime() - Adjust ptp time
+ * @ptp:   PTP clock info
+ * @delta: how much to adjust by, in nanosecs
+ */
+static int cavium_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
+{
+	struct cavium_ptp *clock =
+		container_of(ptp_info, struct cavium_ptp, ptp_info);
+	unsigned long flags;
+
+	spin_lock_irqsave(&clock->spin_lock, flags);
+	timecounter_adjtime(&clock->time_counter, delta);
+	spin_unlock_irqrestore(&clock->spin_lock, flags);
+
+	/* Sync, for network driver to get latest value */
+	smp_mb();
+
+	return 0;
+}
+
+/**
+ * cavium_ptp_gettime() - Get hardware clock time with adjustment
+ * @ptp: PTP clock info
+ * @ts:  timespec
+ */
+static int cavium_ptp_gettime(struct ptp_clock_info *ptp_info,
+			      struct timespec64 *ts)
+{
+	struct cavium_ptp *clock =
+		container_of(ptp_info, struct cavium_ptp, ptp_info);
+	unsigned long flags;
+	u64 nsec;
+
+	spin_lock_irqsave(&clock->spin_lock, flags);
+	nsec = timecounter_read(&clock->time_counter);
+	spin_unlock_irqrestore(&clock->spin_lock, flags);
+
+	*ts = ns_to_timespec64(nsec);
+
+	return 0;
+}
+
+/**
+ * cavium_ptp_settime() - Set hardware clock time. Reset adjustment
+ * @ptp: PTP clock info
+ * @ts:  timespec
+ */
+static int cavium_ptp_settime(struct ptp_clock_info *ptp_info,
+			      const struct timespec64 *ts)
+{
+	struct cavium_ptp *clock =
+		container_of(ptp_info, struct cavium_ptp, ptp_info);
+	unsigned long flags;
+	u64 nsec;
+
+	nsec = timespec64_to_ns(ts);
+
+	spin_lock_irqsave(&clock->spin_lock, flags);
+	timecounter_init(&clock->time_counter, &clock->cycle_counter, nsec);
+	spin_unlock_irqrestore(&clock->spin_lock, flags);
+
+	return 0;
+}
+
+/**
+ * cavium_ptp_enable() - Check if PTP is enabled
+ * @ptp: PTP clock info
+ * @rq:  request
+ * @on:  is it on
+ */
+static int cavium_ptp_enable(struct ptp_clock_info *ptp_info,
+			     struct ptp_clock_request *rq, int on)
+{
+	return -EOPNOTSUPP;
+}
+
+static u64 cavium_ptp_cc_read(const struct cyclecounter *cc)
+{
+	struct cavium_ptp *clock =
+		container_of(cc, struct cavium_ptp, cycle_counter);
+
+	return cavium_ptp_reg_read(clock, PTP_CLOCK_HI);
+}
+
+static int cavium_ptp_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *ent)
+{
+	struct device *dev = &pdev->dev;
+	struct cavium_ptp *clock;
+	struct cyclecounter *cc;
+	u64 clock_cfg;
+	u64 clock_comp;
+	int err;
+
+	clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
+	if (!clock)
+		return -ENOMEM;
+
+	clock->pdev = pdev;
+
+	err = pcim_enable_device(pdev);
+	if (err)
+		return err;
+
+	err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
+	if (err)
+		return err;
+
+	clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
+
+	spin_lock_init(&clock->spin_lock);
+
+	cc = &clock->cycle_counter;
+	cc->read = cavium_ptp_cc_read;
+	cc->mask = CYCLECOUNTER_MASK(64);
+	cc->mult = 1;
+	cc->shift = 0;
+
+	timecounter_init(&clock->time_counter, &clock->cycle_counter,
+			 ktime_to_ns(ktime_get_real()));
+
+	clock->clock_rate = ptp_cavium_clock_get();
+
+	clock->ptp_info = (struct ptp_clock_info) {
+		.owner		= THIS_MODULE,
+		.name		= "ThunderX PTP",
+		.max_adj	= 1000000000ull,
+		.n_ext_ts	= 0,
+		.n_pins		= 0,
+		.pps		= 0,
+		.adjfreq	= cavium_ptp_adjfreq,
+		.adjtime	= cavium_ptp_adjtime,
+		.gettime64	= cavium_ptp_gettime,
+		.settime64	= cavium_ptp_settime,
+		.enable		= cavium_ptp_enable,
+	};
+
+	clock_cfg = cavium_ptp_reg_read(clock, PTP_CLOCK_CFG);
+	clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
+	cavium_ptp_reg_write(clock, PTP_CLOCK_CFG, clock_cfg);
+
+	clock_comp = ((u64)1000000000ull << 32) / clock->clock_rate;
+	cavium_ptp_reg_write(clock, PTP_CLOCK_COMP, clock_comp);
+
+	clock->ptp_clock = ptp_clock_register(&clock->ptp_info, dev);
+	if (IS_ERR(clock->ptp_clock)) {
+		clock_cfg = cavium_ptp_reg_read(clock, PTP_CLOCK_CFG);
+		clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
+		cavium_ptp_reg_write(clock, PTP_CLOCK_CFG, clock_cfg);
+		return PTR_ERR(clock->ptp_clock);
+	}
+
+	pci_set_drvdata(pdev, clock);
+	return 0;
+}
+
+static void cavium_ptp_remove(struct pci_dev *pdev)
+{
+	struct cavium_ptp *clock = pci_get_drvdata(pdev);
+	u64 clock_cfg;
+
+	pci_set_drvdata(pdev, NULL);
+
+	ptp_clock_unregister(clock->ptp_clock);
+
+	clock_cfg = cavium_ptp_reg_read(clock, PTP_CLOCK_CFG);
+	clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
+	cavium_ptp_reg_write(clock, PTP_CLOCK_CFG, clock_cfg);
+}
+
+static const struct pci_device_id cavium_ptp_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_PTP) },
+	{ 0, }
+};
+
+static struct pci_driver cavium_ptp_driver = {
+	.name = DRV_NAME,
+	.id_table = cavium_ptp_id_table,
+	.probe = cavium_ptp_probe,
+	.remove = cavium_ptp_remove,
+};
+
+static int __init cavium_ptp_init_module(void)
+{
+	return pci_register_driver(&cavium_ptp_driver);
+}
+
+static void __exit cavium_ptp_cleanup_module(void)
+{
+	pci_unregister_driver(&cavium_ptp_driver);
+}
+
+module_init(cavium_ptp_init_module);
+module_exit(cavium_ptp_cleanup_module);
+
+MODULE_DESCRIPTION(DRV_NAME);
+MODULE_AUTHOR("Cavium Networks <support@cavium.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, cavium_ptp_id_table);
diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.h b/drivers/net/ethernet/cavium/common/cavium_ptp.h
new file mode 100644
index 000000000000..7a9dcb027a93
--- /dev/null
+++ b/drivers/net/ethernet/cavium/common/cavium_ptp.h
@@ -0,0 +1,78 @@ 
+/*
+ * cavium_ptp.h - PTP 1588 clock on Cavium hardware
+ *
+ * Copyright (c) 2003-2015, 2017 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium, Inc. for more information
+ */
+
+#ifndef CAVIUM_PTP_H
+#define CAVIUM_PTP_H
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
+
+struct cavium_ptp {
+	struct pci_dev *pdev;
+
+	/* Serialize access to cycle_counter, time_counter and hw_registers */
+	spinlock_t spin_lock;
+	struct cyclecounter cycle_counter;
+	struct timecounter time_counter;
+	void __iomem *reg_base;
+
+	u32 clock_rate;
+
+	struct ptp_clock_info ptp_info;
+	struct ptp_clock *ptp_clock;
+};
+
+#ifdef CONFIG_CAVIUM_PTP
+
+struct cavium_ptp *cavium_ptp_get(void);
+void cavium_ptp_put(struct cavium_ptp *ptp);
+
+static inline u64 cavium_ptp_tstamp2time(struct cavium_ptp *ptp, u64 tstamp)
+{
+	unsigned long flags;
+	u64 ret;
+
+	spin_lock_irqsave(&ptp->spin_lock, flags);
+	ret = timecounter_cyc2time(&ptp->time_counter, tstamp);
+	spin_unlock_irqrestore(&ptp->spin_lock, flags);
+
+	return ret;
+}
+
+static inline int cavium_ptp_clock_index(struct cavium_ptp *clock)
+{
+	return ptp_clock_index(clock->ptp_clock);
+}
+
+#else
+
+static inline struct cavium_ptp *cavium_ptp_get(void)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void cavium_ptp_put(struct cavium_ptp *ptp) {}
+
+static inline u64 cavium_ptp_tstamp2time(struct cavium_ptp *ptp, u64 tstamp)
+{
+	return 0;
+}
+
+static inline int cavium_ptp_clock_index(struct cavium_ptp *clock)
+{
+	return -1;
+}
+
+#endif
+
+#endif