otx2_ptp.c (7653B)
1// SPDX-License-Identifier: GPL-2.0 2/* Marvell RVU Ethernet driver 3 * 4 * Copyright (C) 2020 Marvell. 5 * 6 */ 7 8#include <linux/module.h> 9 10#include "otx2_common.h" 11#include "otx2_ptp.h" 12 13static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) 14{ 15 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 16 ptp_info); 17 struct ptp_req *req; 18 19 if (!ptp->nic) 20 return -ENODEV; 21 22 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 23 if (!req) 24 return -ENOMEM; 25 26 req->op = PTP_OP_ADJFINE; 27 req->scaled_ppm = scaled_ppm; 28 29 return otx2_sync_mbox_msg(&ptp->nic->mbox); 30} 31 32static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh) 33{ 34 struct ptp_req *req; 35 36 if (!ptp->nic) 37 return -ENODEV; 38 39 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 40 if (!req) 41 return -ENOMEM; 42 43 req->op = PTP_OP_SET_THRESH; 44 req->thresh = thresh; 45 46 return otx2_sync_mbox_msg(&ptp->nic->mbox); 47} 48 49static u64 ptp_cc_read(const struct cyclecounter *cc) 50{ 51 struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter); 52 struct ptp_req *req; 53 struct ptp_rsp *rsp; 54 int err; 55 56 if (!ptp->nic) 57 return 0; 58 59 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 60 if (!req) 61 return 0; 62 63 req->op = PTP_OP_GET_CLOCK; 64 65 err = otx2_sync_mbox_msg(&ptp->nic->mbox); 66 if (err) 67 return 0; 68 69 rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 70 &req->hdr); 71 if (IS_ERR(rsp)) 72 return 0; 73 74 return rsp->clk; 75} 76 77static u64 ptp_tstmp_read(struct otx2_ptp *ptp) 78{ 79 struct ptp_req *req; 80 struct ptp_rsp *rsp; 81 int err; 82 83 if (!ptp->nic) 84 return 0; 85 86 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 87 if (!req) 88 return 0; 89 90 req->op = PTP_OP_GET_TSTMP; 91 92 err = otx2_sync_mbox_msg(&ptp->nic->mbox); 93 if (err) 94 return 0; 95 96 rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 97 &req->hdr); 98 if (IS_ERR(rsp)) 99 return 0; 100 101 return rsp->clk; 102} 103 104static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) 105{ 106 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 107 ptp_info); 108 struct otx2_nic *pfvf = ptp->nic; 109 110 mutex_lock(&pfvf->mbox.lock); 111 timecounter_adjtime(&ptp->time_counter, delta); 112 mutex_unlock(&pfvf->mbox.lock); 113 114 return 0; 115} 116 117static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info, 118 struct timespec64 *ts) 119{ 120 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 121 ptp_info); 122 struct otx2_nic *pfvf = ptp->nic; 123 u64 nsec; 124 125 mutex_lock(&pfvf->mbox.lock); 126 nsec = timecounter_read(&ptp->time_counter); 127 mutex_unlock(&pfvf->mbox.lock); 128 129 *ts = ns_to_timespec64(nsec); 130 131 return 0; 132} 133 134static int otx2_ptp_settime(struct ptp_clock_info *ptp_info, 135 const struct timespec64 *ts) 136{ 137 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 138 ptp_info); 139 struct otx2_nic *pfvf = ptp->nic; 140 u64 nsec; 141 142 nsec = timespec64_to_ns(ts); 143 144 mutex_lock(&pfvf->mbox.lock); 145 timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec); 146 mutex_unlock(&pfvf->mbox.lock); 147 148 return 0; 149} 150 151static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 152 enum ptp_pin_function func, unsigned int chan) 153{ 154 switch (func) { 155 case PTP_PF_NONE: 156 case PTP_PF_EXTTS: 157 break; 158 case PTP_PF_PEROUT: 159 case PTP_PF_PHYSYNC: 160 return -1; 161 } 162 return 0; 163} 164 165static void otx2_ptp_extts_check(struct work_struct *work) 166{ 167 struct otx2_ptp *ptp = container_of(work, struct otx2_ptp, 168 extts_work.work); 169 struct ptp_clock_event event; 170 u64 tstmp, new_thresh; 171 172 mutex_lock(&ptp->nic->mbox.lock); 173 tstmp = ptp_tstmp_read(ptp); 174 mutex_unlock(&ptp->nic->mbox.lock); 175 176 if (tstmp != ptp->last_extts) { 177 event.type = PTP_CLOCK_EXTTS; 178 event.index = 0; 179 event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp); 180 ptp_clock_event(ptp->ptp_clock, &event); 181 ptp->last_extts = tstmp; 182 183 new_thresh = tstmp % 500000000; 184 if (ptp->thresh != new_thresh) { 185 mutex_lock(&ptp->nic->mbox.lock); 186 ptp_set_thresh(ptp, new_thresh); 187 mutex_unlock(&ptp->nic->mbox.lock); 188 ptp->thresh = new_thresh; 189 } 190 } 191 schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 192} 193 194static int otx2_ptp_enable(struct ptp_clock_info *ptp_info, 195 struct ptp_clock_request *rq, int on) 196{ 197 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 198 ptp_info); 199 int pin; 200 201 if (!ptp->nic) 202 return -ENODEV; 203 204 switch (rq->type) { 205 case PTP_CLK_REQ_EXTTS: 206 pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, 207 rq->extts.index); 208 if (pin < 0) 209 return -EBUSY; 210 if (on) 211 schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 212 else 213 cancel_delayed_work_sync(&ptp->extts_work); 214 return 0; 215 default: 216 break; 217 } 218 return -EOPNOTSUPP; 219} 220 221int otx2_ptp_init(struct otx2_nic *pfvf) 222{ 223 struct otx2_ptp *ptp_ptr; 224 struct cyclecounter *cc; 225 struct ptp_req *req; 226 int err; 227 228 if (is_otx2_lbkvf(pfvf->pdev)) { 229 pfvf->ptp = NULL; 230 return 0; 231 } 232 233 mutex_lock(&pfvf->mbox.lock); 234 /* check if PTP block is available */ 235 req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox); 236 if (!req) { 237 mutex_unlock(&pfvf->mbox.lock); 238 return -ENOMEM; 239 } 240 241 req->op = PTP_OP_GET_CLOCK; 242 243 err = otx2_sync_mbox_msg(&pfvf->mbox); 244 if (err) { 245 mutex_unlock(&pfvf->mbox.lock); 246 return err; 247 } 248 mutex_unlock(&pfvf->mbox.lock); 249 250 ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL); 251 if (!ptp_ptr) { 252 err = -ENOMEM; 253 goto error; 254 } 255 256 ptp_ptr->nic = pfvf; 257 258 cc = &ptp_ptr->cycle_counter; 259 cc->read = ptp_cc_read; 260 cc->mask = CYCLECOUNTER_MASK(64); 261 cc->mult = 1; 262 cc->shift = 0; 263 264 timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter, 265 ktime_to_ns(ktime_get_real())); 266 267 snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP"); 268 ptp_ptr->extts_config.index = 0; 269 ptp_ptr->extts_config.func = PTP_PF_NONE; 270 271 ptp_ptr->ptp_info = (struct ptp_clock_info) { 272 .owner = THIS_MODULE, 273 .name = "OcteonTX2 PTP", 274 .max_adj = 1000000000ull, 275 .n_ext_ts = 1, 276 .n_pins = 1, 277 .pps = 0, 278 .pin_config = &ptp_ptr->extts_config, 279 .adjfine = otx2_ptp_adjfine, 280 .adjtime = otx2_ptp_adjtime, 281 .gettime64 = otx2_ptp_gettime, 282 .settime64 = otx2_ptp_settime, 283 .enable = otx2_ptp_enable, 284 .verify = otx2_ptp_verify_pin, 285 }; 286 287 INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check); 288 289 ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev); 290 if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) { 291 err = ptp_ptr->ptp_clock ? 292 PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV; 293 kfree(ptp_ptr); 294 goto error; 295 } 296 297 if (is_dev_otx2(pfvf->pdev)) { 298 ptp_ptr->convert_rx_ptp_tstmp = &otx2_ptp_convert_rx_timestamp; 299 ptp_ptr->convert_tx_ptp_tstmp = &otx2_ptp_convert_tx_timestamp; 300 } else { 301 ptp_ptr->convert_rx_ptp_tstmp = &cn10k_ptp_convert_timestamp; 302 ptp_ptr->convert_tx_ptp_tstmp = &cn10k_ptp_convert_timestamp; 303 } 304 305 pfvf->ptp = ptp_ptr; 306 307error: 308 return err; 309} 310EXPORT_SYMBOL_GPL(otx2_ptp_init); 311 312void otx2_ptp_destroy(struct otx2_nic *pfvf) 313{ 314 struct otx2_ptp *ptp = pfvf->ptp; 315 316 if (!ptp) 317 return; 318 319 ptp_clock_unregister(ptp->ptp_clock); 320 kfree(ptp); 321 pfvf->ptp = NULL; 322} 323EXPORT_SYMBOL_GPL(otx2_ptp_destroy); 324 325int otx2_ptp_clock_index(struct otx2_nic *pfvf) 326{ 327 if (!pfvf->ptp) 328 return -ENODEV; 329 330 return ptp_clock_index(pfvf->ptp->ptp_clock); 331} 332EXPORT_SYMBOL_GPL(otx2_ptp_clock_index); 333 334int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns) 335{ 336 if (!pfvf->ptp) 337 return -ENODEV; 338 339 *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); 340 341 return 0; 342} 343EXPORT_SYMBOL_GPL(otx2_ptp_tstamp2time); 344 345MODULE_AUTHOR("Sunil Goutham <sgoutham@marvell.com>"); 346MODULE_DESCRIPTION("Marvell RVU NIC PTP Driver"); 347MODULE_LICENSE("GPL v2");