mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-19 22:11:22 +00:00
Add the capability to set parameters through the devlink framework.
The parameter used for controlling PHC (enable/disable) details
are as follows:
- Name: enable_phc
- Type: Boolean (true - enable/false - disable)
- Mode: DEVLINK_PARAM_CMODE_DRIVERINIT
- Effect: Changes take place during driver initialization,
any changes require a devlink reload to take effect.
Signed-off-by: David Arinzon <darinzon@amazon.com>
Link: https://patch.msgid.link/20250617110545.5659-7-darinzon@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
233 lines
5.5 KiB
C
233 lines
5.5 KiB
C
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
|
/*
|
|
* Copyright 2015-2022 Amazon.com, Inc. or its affiliates. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/pci.h>
|
|
#include "ena_netdev.h"
|
|
#include "ena_phc.h"
|
|
#include "ena_devlink.h"
|
|
|
|
static int ena_phc_adjtime(struct ptp_clock_info *clock_info, s64 delta)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static int ena_phc_adjfine(struct ptp_clock_info *clock_info, long scaled_ppm)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static int ena_phc_feature_enable(struct ptp_clock_info *clock_info,
|
|
struct ptp_clock_request *rq,
|
|
int on)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static int ena_phc_gettimex64(struct ptp_clock_info *clock_info,
|
|
struct timespec64 *ts,
|
|
struct ptp_system_timestamp *sts)
|
|
{
|
|
struct ena_phc_info *phc_info =
|
|
container_of(clock_info, struct ena_phc_info, clock_info);
|
|
unsigned long flags;
|
|
u64 timestamp_nsec;
|
|
int rc;
|
|
|
|
spin_lock_irqsave(&phc_info->lock, flags);
|
|
|
|
ptp_read_system_prets(sts);
|
|
|
|
rc = ena_com_phc_get_timestamp(phc_info->adapter->ena_dev,
|
|
×tamp_nsec);
|
|
|
|
ptp_read_system_postts(sts);
|
|
|
|
spin_unlock_irqrestore(&phc_info->lock, flags);
|
|
|
|
*ts = ns_to_timespec64(timestamp_nsec);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int ena_phc_settime64(struct ptp_clock_info *clock_info,
|
|
const struct timespec64 *ts)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static struct ptp_clock_info ena_ptp_clock_info = {
|
|
.owner = THIS_MODULE,
|
|
.n_alarm = 0,
|
|
.n_ext_ts = 0,
|
|
.n_per_out = 0,
|
|
.pps = 0,
|
|
.adjtime = ena_phc_adjtime,
|
|
.adjfine = ena_phc_adjfine,
|
|
.gettimex64 = ena_phc_gettimex64,
|
|
.settime64 = ena_phc_settime64,
|
|
.enable = ena_phc_feature_enable,
|
|
};
|
|
|
|
/* Enable/Disable PHC by the kernel, affects on the next init flow */
|
|
void ena_phc_enable(struct ena_adapter *adapter, bool enable)
|
|
{
|
|
struct ena_phc_info *phc_info = adapter->phc_info;
|
|
|
|
if (!phc_info) {
|
|
netdev_err(adapter->netdev, "phc_info is not allocated\n");
|
|
return;
|
|
}
|
|
|
|
phc_info->enabled = enable;
|
|
}
|
|
|
|
/* Check if PHC is enabled by the kernel */
|
|
bool ena_phc_is_enabled(struct ena_adapter *adapter)
|
|
{
|
|
struct ena_phc_info *phc_info = adapter->phc_info;
|
|
|
|
return (phc_info && phc_info->enabled);
|
|
}
|
|
|
|
/* PHC is activated if ptp clock is registered in the kernel */
|
|
bool ena_phc_is_active(struct ena_adapter *adapter)
|
|
{
|
|
struct ena_phc_info *phc_info = adapter->phc_info;
|
|
|
|
return (phc_info && phc_info->clock);
|
|
}
|
|
|
|
static int ena_phc_register(struct ena_adapter *adapter)
|
|
{
|
|
struct pci_dev *pdev = adapter->pdev;
|
|
struct ptp_clock_info *clock_info;
|
|
struct ena_phc_info *phc_info;
|
|
int rc = 0;
|
|
|
|
phc_info = adapter->phc_info;
|
|
clock_info = &phc_info->clock_info;
|
|
|
|
/* PHC may already be registered in case of a reset */
|
|
if (ena_phc_is_active(adapter))
|
|
return 0;
|
|
|
|
phc_info->adapter = adapter;
|
|
|
|
spin_lock_init(&phc_info->lock);
|
|
|
|
/* Fill the ptp_clock_info struct and register PTP clock */
|
|
*clock_info = ena_ptp_clock_info;
|
|
snprintf(clock_info->name,
|
|
sizeof(clock_info->name),
|
|
"ena-ptp-%02x",
|
|
PCI_SLOT(pdev->devfn));
|
|
|
|
phc_info->clock = ptp_clock_register(clock_info, &pdev->dev);
|
|
if (IS_ERR(phc_info->clock)) {
|
|
rc = PTR_ERR(phc_info->clock);
|
|
netdev_err(adapter->netdev, "Failed registering ptp clock, error: %d\n",
|
|
rc);
|
|
phc_info->clock = NULL;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void ena_phc_unregister(struct ena_adapter *adapter)
|
|
{
|
|
struct ena_phc_info *phc_info = adapter->phc_info;
|
|
|
|
/* During reset flow, PHC must stay registered
|
|
* to keep kernel's PHC index
|
|
*/
|
|
if (ena_phc_is_active(adapter) &&
|
|
!test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) {
|
|
ptp_clock_unregister(phc_info->clock);
|
|
phc_info->clock = NULL;
|
|
}
|
|
}
|
|
|
|
int ena_phc_alloc(struct ena_adapter *adapter)
|
|
{
|
|
/* Allocate driver specific PHC info */
|
|
adapter->phc_info = vzalloc(sizeof(*adapter->phc_info));
|
|
if (unlikely(!adapter->phc_info)) {
|
|
netdev_err(adapter->netdev, "Failed to alloc phc_info\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ena_phc_free(struct ena_adapter *adapter)
|
|
{
|
|
if (adapter->phc_info) {
|
|
vfree(adapter->phc_info);
|
|
adapter->phc_info = NULL;
|
|
}
|
|
}
|
|
|
|
int ena_phc_init(struct ena_adapter *adapter)
|
|
{
|
|
struct ena_com_dev *ena_dev = adapter->ena_dev;
|
|
struct net_device *netdev = adapter->netdev;
|
|
int rc = -EOPNOTSUPP;
|
|
|
|
/* Validate PHC feature is supported in the device */
|
|
if (!ena_com_phc_supported(ena_dev)) {
|
|
netdev_dbg(netdev, "PHC feature is not supported by the device\n");
|
|
goto err_ena_com_phc_init;
|
|
}
|
|
|
|
/* Validate PHC feature is enabled by the kernel */
|
|
if (!ena_phc_is_enabled(adapter)) {
|
|
netdev_dbg(netdev, "PHC feature is not enabled by the kernel\n");
|
|
goto err_ena_com_phc_init;
|
|
}
|
|
|
|
/* Initialize device specific PHC info */
|
|
rc = ena_com_phc_init(ena_dev);
|
|
if (unlikely(rc)) {
|
|
netdev_err(netdev, "Failed to init phc, error: %d\n", rc);
|
|
goto err_ena_com_phc_init;
|
|
}
|
|
|
|
/* Configure PHC feature in driver and device */
|
|
rc = ena_com_phc_config(ena_dev);
|
|
if (unlikely(rc)) {
|
|
netdev_err(netdev, "Failed to config phc, error: %d\n", rc);
|
|
goto err_ena_com_phc_config;
|
|
}
|
|
|
|
/* Register to PTP class driver */
|
|
rc = ena_phc_register(adapter);
|
|
if (unlikely(rc)) {
|
|
netdev_err(netdev, "Failed to register phc, error: %d\n", rc);
|
|
goto err_ena_com_phc_config;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_ena_com_phc_config:
|
|
ena_com_phc_destroy(ena_dev);
|
|
err_ena_com_phc_init:
|
|
ena_phc_enable(adapter, false);
|
|
ena_devlink_disable_phc_param(adapter->devlink);
|
|
return rc;
|
|
}
|
|
|
|
void ena_phc_destroy(struct ena_adapter *adapter)
|
|
{
|
|
ena_phc_unregister(adapter);
|
|
ena_com_phc_destroy(adapter->ena_dev);
|
|
}
|
|
|
|
int ena_phc_get_index(struct ena_adapter *adapter)
|
|
{
|
|
if (ena_phc_is_active(adapter))
|
|
return ptp_clock_index(adapter->phc_info->clock);
|
|
|
|
return -1;
|
|
}
|