File Index
Files and directories
Sign in
FILE

ena_phc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/amazon/ena/ena_phc.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/*
  3 * Copyright 2015-2022 Amazon.com, Inc. or its affiliates. All rights reserved.
  4 */
  5
  6#include <linux/pci.h>
  7#include "ena_netdev.h"
  8#include "ena_phc.h"
  9#include "ena_devlink.h"
 10
 11static int ena_phc_adjtime(struct ptp_clock_info *clock_info, s64 delta)
 12{
 13	return -EOPNOTSUPP;
 14}
 15
 16static int ena_phc_adjfine(struct ptp_clock_info *clock_info, long scaled_ppm)
 17{
 18	return -EOPNOTSUPP;
 19}
 20
 21static int ena_phc_feature_enable(struct ptp_clock_info *clock_info,
 22				  struct ptp_clock_request *rq,
 23				  int on)
 24{
 25	return -EOPNOTSUPP;
 26}
 27
 28static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
 29			      struct timespec64 *ts,
 30			      struct ptp_system_timestamp *sts)
 31{
 32	struct ena_phc_info *phc_info =
 33		container_of(clock_info, struct ena_phc_info, clock_info);
 34	unsigned long flags;
 35	u64 timestamp_nsec;
 36	int rc;
 37
 38	spin_lock_irqsave(&phc_info->lock, flags);
 39
 40	ptp_read_system_prets(sts);
 41
 42	rc = ena_com_phc_get_timestamp(phc_info->adapter->ena_dev,
 43				       &timestamp_nsec);
 44
 45	ptp_read_system_postts(sts);
 46
 47	spin_unlock_irqrestore(&phc_info->lock, flags);
 48
 49	*ts = ns_to_timespec64(timestamp_nsec);
 50
 51	return rc;
 52}
 53
 54static int ena_phc_settime64(struct ptp_clock_info *clock_info,
 55			     const struct timespec64 *ts)
 56{
 57	return -EOPNOTSUPP;
 58}
 59
 60static struct ptp_clock_info ena_ptp_clock_info = {
 61	.owner		= THIS_MODULE,
 62	.n_alarm	= 0,
 63	.n_ext_ts	= 0,
 64	.n_per_out	= 0,
 65	.pps		= 0,
 66	.adjtime	= ena_phc_adjtime,
 67	.adjfine	= ena_phc_adjfine,
 68	.gettimex64	= ena_phc_gettimex64,
 69	.settime64	= ena_phc_settime64,
 70	.enable		= ena_phc_feature_enable,
 71};
 72
 73/* Enable/Disable PHC by the kernel, affects on the next init flow */
 74void ena_phc_enable(struct ena_adapter *adapter, bool enable)
 75{
 76	struct ena_phc_info *phc_info = adapter->phc_info;
 77
 78	if (!phc_info) {
 79		netdev_err(adapter->netdev, "phc_info is not allocated\n");
 80		return;
 81	}
 82
 83	phc_info->enabled = enable;
 84}
 85
 86/* Check if PHC is enabled by the kernel */
 87bool ena_phc_is_enabled(struct ena_adapter *adapter)
 88{
 89	struct ena_phc_info *phc_info = adapter->phc_info;
 90
 91	return (phc_info && phc_info->enabled);
 92}
 93
 94/* PHC is activated if ptp clock is registered in the kernel */
 95bool ena_phc_is_active(struct ena_adapter *adapter)
 96{
 97	struct ena_phc_info *phc_info = adapter->phc_info;
 98
 99	return (phc_info && phc_info->clock);
100}
101
102static int ena_phc_register(struct ena_adapter *adapter)
103{
104	struct pci_dev *pdev = adapter->pdev;
105	struct ptp_clock_info *clock_info;
106	struct ena_phc_info *phc_info;
107	int rc = 0;
108
109	phc_info = adapter->phc_info;
110	clock_info = &phc_info->clock_info;
111
112	/* PHC may already be registered in case of a reset */
113	if (ena_phc_is_active(adapter))
114		return 0;
115
116	phc_info->adapter = adapter;
117
118	spin_lock_init(&phc_info->lock);
119
120	/* Fill the ptp_clock_info struct and register PTP clock */
121	*clock_info = ena_ptp_clock_info;
122	snprintf(clock_info->name,
123		 sizeof(clock_info->name),
124		 "ena-ptp-%02x",
125		 PCI_SLOT(pdev->devfn));
126
127	phc_info->clock = ptp_clock_register(clock_info, &pdev->dev);
128	if (IS_ERR(phc_info->clock)) {
129		rc = PTR_ERR(phc_info->clock);
130		netdev_err(adapter->netdev, "Failed registering ptp clock, error: %d\n",
131			   rc);
132		phc_info->clock = NULL;
133	}
134
135	return rc;
136}
137
138static void ena_phc_unregister(struct ena_adapter *adapter)
139{
140	struct ena_phc_info *phc_info = adapter->phc_info;
141
142	/* During reset flow, PHC must stay registered
143	 * to keep kernel's PHC index
144	 */
145	if (ena_phc_is_active(adapter) &&
146	    !test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
147		ptp_clock_unregister(phc_info->clock);
148		phc_info->clock = NULL;
149	}
150}
151
152int ena_phc_alloc(struct ena_adapter *adapter)
153{
154	/* Allocate driver specific PHC info */
155	adapter->phc_info = vzalloc(sizeof(*adapter->phc_info));
156	if (unlikely(!adapter->phc_info)) {
157		netdev_err(adapter->netdev, "Failed to alloc phc_info\n");
158		return -ENOMEM;
159	}
160
161	return 0;
162}
163
164void ena_phc_free(struct ena_adapter *adapter)
165{
166	if (adapter->phc_info) {
167		vfree(adapter->phc_info);
168		adapter->phc_info = NULL;
169	}
170}
171
172int ena_phc_init(struct ena_adapter *adapter)
173{
174	struct ena_com_dev *ena_dev = adapter->ena_dev;
175	struct net_device *netdev = adapter->netdev;
176	int rc = -EOPNOTSUPP;
177
178	/* Validate PHC feature is supported in the device */
179	if (!ena_com_phc_supported(ena_dev)) {
180		netdev_dbg(netdev, "PHC feature is not supported by the device\n");
181		goto err_ena_com_phc_init;
182	}
183
184	/* Validate PHC feature is enabled by the kernel */
185	if (!ena_phc_is_enabled(adapter)) {
186		netdev_dbg(netdev, "PHC feature is not enabled by the kernel\n");
187		goto err_ena_com_phc_init;
188	}
189
190	/* Initialize device specific PHC info */
191	rc = ena_com_phc_init(ena_dev);
192	if (unlikely(rc)) {
193		netdev_err(netdev, "Failed to init phc, error: %d\n", rc);
194		goto err_ena_com_phc_init;
195	}
196
197	/* Configure PHC feature in driver and device */
198	rc = ena_com_phc_config(ena_dev);
199	if (unlikely(rc)) {
200		netdev_err(netdev, "Failed to config phc, error: %d\n", rc);
201		goto err_ena_com_phc_config;
202	}
203
204	/* Register to PTP class driver */
205	rc = ena_phc_register(adapter);
206	if (unlikely(rc)) {
207		netdev_err(netdev, "Failed to register phc, error: %d\n", rc);
208		goto err_ena_com_phc_config;
209	}
210
211	return 0;
212
213err_ena_com_phc_config:
214	ena_com_phc_destroy(ena_dev);
215err_ena_com_phc_init:
216	ena_phc_enable(adapter, false);
217	ena_devlink_disable_phc_param(adapter->devlink);
218	return rc;
219}
220
221void ena_phc_destroy(struct ena_adapter *adapter)
222{
223	ena_phc_unregister(adapter);
224	ena_com_phc_destroy(adapter->ena_dev);
225}
226
227int ena_phc_get_index(struct ena_adapter *adapter)
228{
229	if (ena_phc_is_active(adapter))
230		return ptp_clock_index(adapter->phc_info->clock);
231
232	return -1;
233}
~/ Read-only file preview.