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