525 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell RVU Ethernet driver3 *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 bool is_tstmp_atomic_update_supported(struct otx2_ptp *ptp)14{15 struct ptp_get_cap_rsp *rsp;16 struct msg_req *req;17 int err;18 19 if (!ptp->nic)20 return false;21 22 mutex_lock(&ptp->nic->mbox.lock);23 req = otx2_mbox_alloc_msg_ptp_get_cap(&ptp->nic->mbox);24 if (!req) {25 mutex_unlock(&ptp->nic->mbox.lock);26 return false;27 }28 29 err = otx2_sync_mbox_msg(&ptp->nic->mbox);30 if (err) {31 mutex_unlock(&ptp->nic->mbox.lock);32 return false;33 }34 rsp = (struct ptp_get_cap_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,35 &req->hdr);36 mutex_unlock(&ptp->nic->mbox.lock);37 38 if (IS_ERR(rsp))39 return false;40 41 if (rsp->cap & PTP_CAP_HW_ATOMIC_UPDATE)42 return true;43 44 return false;45}46 47static int otx2_ptp_hw_adjtime(struct ptp_clock_info *ptp_info, s64 delta)48{49 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,50 ptp_info);51 struct otx2_nic *pfvf = ptp->nic;52 struct ptp_req *req;53 int rc;54 55 if (!ptp->nic)56 return -ENODEV;57 58 mutex_lock(&pfvf->mbox.lock);59 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);60 if (!req) {61 mutex_unlock(&pfvf->mbox.lock);62 return -ENOMEM;63 }64 req->op = PTP_OP_ADJTIME;65 req->delta = delta;66 rc = otx2_sync_mbox_msg(&ptp->nic->mbox);67 mutex_unlock(&pfvf->mbox.lock);68 69 return rc;70}71 72static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp)73{74 struct ptp_req *req;75 struct ptp_rsp *rsp;76 int err;77 78 if (!ptp->nic)79 return 0;80 81 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);82 if (!req)83 return 0;84 85 req->op = PTP_OP_GET_CLOCK;86 87 err = otx2_sync_mbox_msg(&ptp->nic->mbox);88 if (err)89 return 0;90 91 rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,92 &req->hdr);93 if (IS_ERR(rsp))94 return 0;95 96 return rsp->clk;97}98 99static int otx2_ptp_hw_gettime(struct ptp_clock_info *ptp_info,100 struct timespec64 *ts)101{102 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,103 ptp_info);104 u64 tstamp;105 106 tstamp = otx2_ptp_get_clock(ptp);107 108 *ts = ns_to_timespec64(tstamp);109 return 0;110}111 112static int otx2_ptp_hw_settime(struct ptp_clock_info *ptp_info,113 const struct timespec64 *ts)114{115 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,116 ptp_info);117 struct otx2_nic *pfvf = ptp->nic;118 struct ptp_req *req;119 u64 nsec;120 int rc;121 122 if (!ptp->nic)123 return -ENODEV;124 125 nsec = timespec64_to_ns(ts);126 127 mutex_lock(&pfvf->mbox.lock);128 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);129 if (!req) {130 mutex_unlock(&pfvf->mbox.lock);131 return -ENOMEM;132 }133 134 req->op = PTP_OP_SET_CLOCK;135 req->clk = nsec;136 rc = otx2_sync_mbox_msg(&ptp->nic->mbox);137 mutex_unlock(&pfvf->mbox.lock);138 139 return rc;140}141 142static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)143{144 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,145 ptp_info);146 struct ptp_req *req;147 148 if (!ptp->nic)149 return -ENODEV;150 151 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);152 if (!req)153 return -ENOMEM;154 155 req->op = PTP_OP_ADJFINE;156 req->scaled_ppm = scaled_ppm;157 158 return otx2_sync_mbox_msg(&ptp->nic->mbox);159}160 161static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh)162{163 struct ptp_req *req;164 165 if (!ptp->nic)166 return -ENODEV;167 168 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);169 if (!req)170 return -ENOMEM;171 172 req->op = PTP_OP_SET_THRESH;173 req->thresh = thresh;174 175 return otx2_sync_mbox_msg(&ptp->nic->mbox);176}177 178static int ptp_pps_on(struct otx2_ptp *ptp, int on, u64 period)179{180 struct ptp_req *req;181 182 if (!ptp->nic)183 return -ENODEV;184 185 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);186 if (!req)187 return -ENOMEM;188 189 req->op = PTP_OP_PPS_ON;190 req->pps_on = on;191 req->period = period;192 193 return otx2_sync_mbox_msg(&ptp->nic->mbox);194}195 196static u64 ptp_cc_read(const struct cyclecounter *cc)197{198 struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter);199 200 return otx2_ptp_get_clock(ptp);201}202 203static u64 ptp_tstmp_read(struct otx2_ptp *ptp)204{205 struct ptp_req *req;206 struct ptp_rsp *rsp;207 int err;208 209 if (!ptp->nic)210 return 0;211 212 req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);213 if (!req)214 return 0;215 216 req->op = PTP_OP_GET_TSTMP;217 218 err = otx2_sync_mbox_msg(&ptp->nic->mbox);219 if (err)220 return 0;221 222 rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,223 &req->hdr);224 if (IS_ERR(rsp))225 return 0;226 227 return rsp->clk;228}229 230static int otx2_ptp_tc_adjtime(struct ptp_clock_info *ptp_info, s64 delta)231{232 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,233 ptp_info);234 struct otx2_nic *pfvf = ptp->nic;235 236 mutex_lock(&pfvf->mbox.lock);237 timecounter_adjtime(&ptp->time_counter, delta);238 mutex_unlock(&pfvf->mbox.lock);239 240 return 0;241}242 243static int otx2_ptp_tc_gettime(struct ptp_clock_info *ptp_info,244 struct timespec64 *ts)245{246 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,247 ptp_info);248 u64 tstamp;249 250 mutex_lock(&ptp->nic->mbox.lock);251 tstamp = timecounter_read(&ptp->time_counter);252 mutex_unlock(&ptp->nic->mbox.lock);253 *ts = ns_to_timespec64(tstamp);254 255 return 0;256}257 258static int otx2_ptp_tc_settime(struct ptp_clock_info *ptp_info,259 const struct timespec64 *ts)260{261 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,262 ptp_info);263 u64 nsec;264 265 nsec = timespec64_to_ns(ts);266 267 mutex_lock(&ptp->nic->mbox.lock);268 timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);269 mutex_unlock(&ptp->nic->mbox.lock);270 271 return 0;272}273 274static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,275 enum ptp_pin_function func, unsigned int chan)276{277 switch (func) {278 case PTP_PF_NONE:279 case PTP_PF_EXTTS:280 case PTP_PF_PEROUT:281 break;282 case PTP_PF_PHYSYNC:283 return -1;284 }285 return 0;286}287 288static u64 otx2_ptp_hw_tstamp2time(const struct timecounter *time_counter, u64 tstamp)289{290 /* On HW which supports atomic updates, timecounter is not initialized */291 return tstamp;292}293 294static void otx2_ptp_extts_check(struct work_struct *work)295{296 struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,297 extts_work.work);298 struct ptp_clock_event event;299 u64 tstmp, new_thresh;300 301 mutex_lock(&ptp->nic->mbox.lock);302 tstmp = ptp_tstmp_read(ptp);303 mutex_unlock(&ptp->nic->mbox.lock);304 305 if (tstmp != ptp->last_extts) {306 event.type = PTP_CLOCK_EXTTS;307 event.index = 0;308 event.timestamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstmp);309 ptp_clock_event(ptp->ptp_clock, &event);310 new_thresh = tstmp % 500000000;311 if (ptp->thresh != new_thresh) {312 mutex_lock(&ptp->nic->mbox.lock);313 ptp_set_thresh(ptp, new_thresh);314 mutex_unlock(&ptp->nic->mbox.lock);315 ptp->thresh = new_thresh;316 }317 ptp->last_extts = tstmp;318 }319 schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));320}321 322static void otx2_sync_tstamp(struct work_struct *work)323{324 struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,325 synctstamp_work.work);326 struct otx2_nic *pfvf = ptp->nic;327 u64 tstamp;328 329 mutex_lock(&pfvf->mbox.lock);330 tstamp = otx2_ptp_get_clock(ptp);331 mutex_unlock(&pfvf->mbox.lock);332 333 ptp->tstamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstamp);334 ptp->base_ns = tstamp % NSEC_PER_SEC;335 336 schedule_delayed_work(&ptp->synctstamp_work, msecs_to_jiffies(250));337}338 339static int otx2_ptp_enable(struct ptp_clock_info *ptp_info,340 struct ptp_clock_request *rq, int on)341{342 struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,343 ptp_info);344 u64 period = 0;345 int pin;346 347 if (!ptp->nic)348 return -ENODEV;349 350 switch (rq->type) {351 case PTP_CLK_REQ_EXTTS:352 pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS,353 rq->extts.index);354 if (pin < 0)355 return -EBUSY;356 if (on)357 schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200));358 else359 cancel_delayed_work_sync(&ptp->extts_work);360 361 return 0;362 case PTP_CLK_REQ_PEROUT:363 if (rq->perout.flags)364 return -EOPNOTSUPP;365 366 if (rq->perout.index >= ptp_info->n_pins)367 return -EINVAL;368 if (on) {369 period = rq->perout.period.sec * NSEC_PER_SEC +370 rq->perout.period.nsec;371 ptp_pps_on(ptp, on, period);372 } else {373 ptp_pps_on(ptp, on, period);374 }375 return 0;376 default:377 break;378 }379 return -EOPNOTSUPP;380}381 382int otx2_ptp_init(struct otx2_nic *pfvf)383{384 struct otx2_ptp *ptp_ptr;385 struct cyclecounter *cc;386 struct ptp_req *req;387 int err;388 389 if (is_otx2_lbkvf(pfvf->pdev)) {390 pfvf->ptp = NULL;391 return 0;392 }393 394 mutex_lock(&pfvf->mbox.lock);395 /* check if PTP block is available */396 req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox);397 if (!req) {398 mutex_unlock(&pfvf->mbox.lock);399 return -ENOMEM;400 }401 402 req->op = PTP_OP_GET_CLOCK;403 404 err = otx2_sync_mbox_msg(&pfvf->mbox);405 if (err) {406 mutex_unlock(&pfvf->mbox.lock);407 return err;408 }409 mutex_unlock(&pfvf->mbox.lock);410 411 ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL);412 if (!ptp_ptr) {413 err = -ENOMEM;414 goto error;415 }416 417 ptp_ptr->nic = pfvf;418 419 snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP");420 ptp_ptr->extts_config.index = 0;421 ptp_ptr->extts_config.func = PTP_PF_NONE;422 423 ptp_ptr->ptp_info = (struct ptp_clock_info) {424 .owner = THIS_MODULE,425 .name = "OcteonTX2 PTP",426 .max_adj = 1000000000ull,427 .n_ext_ts = 1,428 .n_per_out = 1,429 .n_pins = 1,430 .pps = 0,431 .pin_config = &ptp_ptr->extts_config,432 .adjfine = otx2_ptp_adjfine,433 .enable = otx2_ptp_enable,434 .verify = otx2_ptp_verify_pin,435 };436 437 /* Check whether hardware supports atomic updates to timestamp */438 if (is_tstmp_atomic_update_supported(ptp_ptr)) {439 ptp_ptr->ptp_info.adjtime = otx2_ptp_hw_adjtime;440 ptp_ptr->ptp_info.gettime64 = otx2_ptp_hw_gettime;441 ptp_ptr->ptp_info.settime64 = otx2_ptp_hw_settime;442 443 ptp_ptr->ptp_tstamp2nsec = otx2_ptp_hw_tstamp2time;444 } else {445 ptp_ptr->ptp_info.adjtime = otx2_ptp_tc_adjtime;446 ptp_ptr->ptp_info.gettime64 = otx2_ptp_tc_gettime;447 ptp_ptr->ptp_info.settime64 = otx2_ptp_tc_settime;448 449 cc = &ptp_ptr->cycle_counter;450 cc->read = ptp_cc_read;451 cc->mask = CYCLECOUNTER_MASK(64);452 cc->mult = 1;453 cc->shift = 0;454 ptp_ptr->ptp_tstamp2nsec = timecounter_cyc2time;455 456 timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,457 ktime_to_ns(ktime_get_real()));458 }459 460 INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check);461 462 ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);463 if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) {464 err = ptp_ptr->ptp_clock ?465 PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV;466 kfree(ptp_ptr);467 goto error;468 }469 470 if (is_dev_otx2(pfvf->pdev)) {471 ptp_ptr->convert_rx_ptp_tstmp = &otx2_ptp_convert_rx_timestamp;472 ptp_ptr->convert_tx_ptp_tstmp = &otx2_ptp_convert_tx_timestamp;473 } else {474 ptp_ptr->convert_rx_ptp_tstmp = &cn10k_ptp_convert_timestamp;475 ptp_ptr->convert_tx_ptp_tstmp = &cn10k_ptp_convert_timestamp;476 }477 478 INIT_DELAYED_WORK(&ptp_ptr->synctstamp_work, otx2_sync_tstamp);479 480 pfvf->ptp = ptp_ptr;481 482error:483 return err;484}485EXPORT_SYMBOL_GPL(otx2_ptp_init);486 487void otx2_ptp_destroy(struct otx2_nic *pfvf)488{489 struct otx2_ptp *ptp = pfvf->ptp;490 491 if (!ptp)492 return;493 494 cancel_delayed_work(&pfvf->ptp->synctstamp_work);495 496 ptp_clock_unregister(ptp->ptp_clock);497 kfree(ptp);498 pfvf->ptp = NULL;499}500EXPORT_SYMBOL_GPL(otx2_ptp_destroy);501 502int otx2_ptp_clock_index(struct otx2_nic *pfvf)503{504 if (!pfvf->ptp)505 return -ENODEV;506 507 return ptp_clock_index(pfvf->ptp->ptp_clock);508}509EXPORT_SYMBOL_GPL(otx2_ptp_clock_index);510 511int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)512{513 if (!pfvf->ptp)514 return -ENODEV;515 516 *tsns = pfvf->ptp->ptp_tstamp2nsec(&pfvf->ptp->time_counter, tstamp);517 518 return 0;519}520EXPORT_SYMBOL_GPL(otx2_ptp_tstamp2time);521 522MODULE_AUTHOR("Sunil Goutham <sgoutham@marvell.com>");523MODULE_DESCRIPTION("Marvell RVU NIC PTP Driver");524MODULE_LICENSE("GPL v2");525