cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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");