linux/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Marvell RVU Ethernet driver
   3 *
   4 * Copyright (C) 2020 Marvell.
   5 *
   6 */
   7
   8#include "otx2_common.h"
   9#include "otx2_ptp.h"
  10
  11static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
  12{
  13        struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
  14                                            ptp_info);
  15        struct ptp_req *req;
  16
  17        if (!ptp->nic)
  18                return -ENODEV;
  19
  20        req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
  21        if (!req)
  22                return -ENOMEM;
  23
  24        req->op = PTP_OP_ADJFINE;
  25        req->scaled_ppm = scaled_ppm;
  26
  27        return otx2_sync_mbox_msg(&ptp->nic->mbox);
  28}
  29
  30static u64 ptp_cc_read(const struct cyclecounter *cc)
  31{
  32        struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter);
  33        struct ptp_req *req;
  34        struct ptp_rsp *rsp;
  35        int err;
  36
  37        if (!ptp->nic)
  38                return 0;
  39
  40        req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
  41        if (!req)
  42                return 0;
  43
  44        req->op = PTP_OP_GET_CLOCK;
  45
  46        err = otx2_sync_mbox_msg(&ptp->nic->mbox);
  47        if (err)
  48                return 0;
  49
  50        rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
  51                                                  &req->hdr);
  52        if (IS_ERR(rsp))
  53                return 0;
  54
  55        return rsp->clk;
  56}
  57
  58static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
  59{
  60        struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
  61                                            ptp_info);
  62        struct otx2_nic *pfvf = ptp->nic;
  63
  64        mutex_lock(&pfvf->mbox.lock);
  65        timecounter_adjtime(&ptp->time_counter, delta);
  66        mutex_unlock(&pfvf->mbox.lock);
  67
  68        return 0;
  69}
  70
  71static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info,
  72                            struct timespec64 *ts)
  73{
  74        struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
  75                                            ptp_info);
  76        struct otx2_nic *pfvf = ptp->nic;
  77        u64 nsec;
  78
  79        mutex_lock(&pfvf->mbox.lock);
  80        nsec = timecounter_read(&ptp->time_counter);
  81        mutex_unlock(&pfvf->mbox.lock);
  82
  83        *ts = ns_to_timespec64(nsec);
  84
  85        return 0;
  86}
  87
  88static int otx2_ptp_settime(struct ptp_clock_info *ptp_info,
  89                            const struct timespec64 *ts)
  90{
  91        struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
  92                                            ptp_info);
  93        struct otx2_nic *pfvf = ptp->nic;
  94        u64 nsec;
  95
  96        nsec = timespec64_to_ns(ts);
  97
  98        mutex_lock(&pfvf->mbox.lock);
  99        timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);
 100        mutex_unlock(&pfvf->mbox.lock);
 101
 102        return 0;
 103}
 104
 105static int otx2_ptp_enable(struct ptp_clock_info *ptp_info,
 106                           struct ptp_clock_request *rq, int on)
 107{
 108        return -EOPNOTSUPP;
 109}
 110
 111int otx2_ptp_init(struct otx2_nic *pfvf)
 112{
 113        struct otx2_ptp *ptp_ptr;
 114        struct cyclecounter *cc;
 115        struct ptp_req *req;
 116        int err;
 117
 118        mutex_lock(&pfvf->mbox.lock);
 119        /* check if PTP block is available */
 120        req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox);
 121        if (!req) {
 122                mutex_unlock(&pfvf->mbox.lock);
 123                return -ENOMEM;
 124        }
 125
 126        req->op = PTP_OP_GET_CLOCK;
 127
 128        err = otx2_sync_mbox_msg(&pfvf->mbox);
 129        if (err) {
 130                mutex_unlock(&pfvf->mbox.lock);
 131                return err;
 132        }
 133        mutex_unlock(&pfvf->mbox.lock);
 134
 135        ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL);
 136        if (!ptp_ptr) {
 137                err = -ENOMEM;
 138                goto error;
 139        }
 140
 141        ptp_ptr->nic = pfvf;
 142
 143        cc = &ptp_ptr->cycle_counter;
 144        cc->read = ptp_cc_read;
 145        cc->mask = CYCLECOUNTER_MASK(64);
 146        cc->mult = 1;
 147        cc->shift = 0;
 148
 149        timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
 150                         ktime_to_ns(ktime_get_real()));
 151
 152        ptp_ptr->ptp_info = (struct ptp_clock_info) {
 153                .owner          = THIS_MODULE,
 154                .name           = "OcteonTX2 PTP",
 155                .max_adj        = 1000000000ull,
 156                .n_ext_ts       = 0,
 157                .n_pins         = 0,
 158                .pps            = 0,
 159                .adjfine        = otx2_ptp_adjfine,
 160                .adjtime        = otx2_ptp_adjtime,
 161                .gettime64      = otx2_ptp_gettime,
 162                .settime64      = otx2_ptp_settime,
 163                .enable         = otx2_ptp_enable,
 164        };
 165
 166        ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
 167        if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) {
 168                err = ptp_ptr->ptp_clock ?
 169                      PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV;
 170                kfree(ptp_ptr);
 171                goto error;
 172        }
 173
 174        pfvf->ptp = ptp_ptr;
 175
 176error:
 177        return err;
 178}
 179
 180void otx2_ptp_destroy(struct otx2_nic *pfvf)
 181{
 182        struct otx2_ptp *ptp = pfvf->ptp;
 183
 184        if (!ptp)
 185                return;
 186
 187        ptp_clock_unregister(ptp->ptp_clock);
 188        kfree(ptp);
 189        pfvf->ptp = NULL;
 190}
 191
 192int otx2_ptp_clock_index(struct otx2_nic *pfvf)
 193{
 194        if (!pfvf->ptp)
 195                return -ENODEV;
 196
 197        return ptp_clock_index(pfvf->ptp->ptp_clock);
 198}
 199
 200int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
 201{
 202        if (!pfvf->ptp)
 203                return -ENODEV;
 204
 205        *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
 206
 207        return 0;
 208}
 209