brintos

brintos / linux-shallow public Read only

0
0
Text · 11.5 KiB · 63130ba Raw
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