brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · cbd06d9 Raw
469 lines · c
1/*2 * cxgb4_ptp.c:Chelsio PTP support for T5/T63 *4 * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved.5 *6 * This software is available to you under a choice of one of two7 * licenses.  You may choose to be licensed under the terms of the GNU8 * General Public License (GPL) Version 2, available from the file9 * COPYING in the main directory of this source tree, or the10 * OpenIB.org BSD license below:11 *12 *     Redistribution and use in source and binary forms, with or13 *     without modification, are permitted provided that the following14 *     conditions are met:15 *16 *      - Redistributions of source code must retain the above17 *        copyright notice, this list of conditions and the following18 *        disclaimer.19 *20 *      - Redistributions in binary form must reproduce the above21 *        copyright notice, this list of conditions and the following22 *        disclaimer in the documentation and/or other materials23 *        provided with the distribution.24 *25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE32 * SOFTWARE.33 *34 * Written by: Atul Gupta (atul.gupta@chelsio.com)35 */36 37#include <linux/module.h>38#include <linux/net_tstamp.h>39#include <linux/skbuff.h>40#include <linux/netdevice.h>41#include <linux/pps_kernel.h>42#include <linux/ptp_clock_kernel.h>43#include <linux/ptp_classify.h>44#include <linux/udp.h>45 46#include "cxgb4.h"47#include "t4_hw.h"48#include "t4_regs.h"49#include "t4_msg.h"50#include "t4fw_api.h"51#include "cxgb4_ptp.h"52 53/**54 * cxgb4_ptp_is_ptp_tx - determine whether TX packet is PTP or not55 * @skb: skb of outgoing ptp request56 *57 */58bool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb)59{60	struct udphdr *uh;61 62	uh = udp_hdr(skb);63	return skb->len >= PTP_MIN_LENGTH &&64		skb->len <= PTP_IN_TRANSMIT_PACKET_MAXNUM &&65		likely(skb->protocol == htons(ETH_P_IP)) &&66		ip_hdr(skb)->protocol == IPPROTO_UDP &&67		uh->dest == htons(PTP_EVENT_PORT);68}69 70bool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev)71{72	struct port_info *pi;73 74	pi = netdev_priv(dev);75	return (pi->ptp_enable && cxgb4_xmit_with_hwtstamp(skb) &&76		cxgb4_ptp_is_ptp_tx(skb));77}78 79/**80 * cxgb4_ptp_is_ptp_rx - determine whether RX packet is PTP or not81 * @skb: skb of incoming ptp request82 *83 */84bool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb)85{86	struct udphdr *uh = (struct udphdr *)(skb->data + ETH_HLEN +87					      IPV4_HLEN(skb->data));88 89	return  uh->dest == htons(PTP_EVENT_PORT) &&90		uh->source == htons(PTP_EVENT_PORT);91}92 93/**94 * cxgb4_ptp_read_hwstamp - read timestamp for TX event PTP message95 * @adapter: board private structure96 * @pi: port private structure97 *98 */99void cxgb4_ptp_read_hwstamp(struct adapter *adapter, struct port_info *pi)100{101	struct skb_shared_hwtstamps *skb_ts = NULL;102	u64 tx_ts;103 104	skb_ts = skb_hwtstamps(adapter->ptp_tx_skb);105 106	tx_ts = t4_read_reg(adapter,107			    T5_PORT_REG(pi->port_id, MAC_PORT_TX_TS_VAL_LO));108 109	tx_ts |= (u64)t4_read_reg(adapter,110				  T5_PORT_REG(pi->port_id,111					      MAC_PORT_TX_TS_VAL_HI)) << 32;112	skb_ts->hwtstamp = ns_to_ktime(tx_ts);113	skb_tstamp_tx(adapter->ptp_tx_skb, skb_ts);114	dev_kfree_skb_any(adapter->ptp_tx_skb);115	spin_lock(&adapter->ptp_lock);116	adapter->ptp_tx_skb = NULL;117	spin_unlock(&adapter->ptp_lock);118}119 120/**121 * cxgb4_ptprx_timestamping - Enable Timestamp for RX PTP event message122 * @pi: port private structure123 * @port: pot number124 * @mode: RX mode125 *126 */127int cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode)128{129	struct adapter *adapter = pi->adapter;130	struct fw_ptp_cmd c;131	int err;132 133	memset(&c, 0, sizeof(c));134	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |135				     FW_CMD_REQUEST_F |136				     FW_CMD_WRITE_F |137				     FW_PTP_CMD_PORTID_V(port));138	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));139	c.u.init.sc = FW_PTP_SC_RXTIME_STAMP;140	c.u.init.mode = cpu_to_be16(mode);141 142	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);143	if (err < 0)144		dev_err(adapter->pdev_dev,145			"PTP: %s error %d\n", __func__, -err);146	return err;147}148 149int cxgb4_ptp_txtype(struct adapter *adapter, u8 port)150{151	struct fw_ptp_cmd c;152	int err;153 154	memset(&c, 0, sizeof(c));155	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |156				     FW_CMD_REQUEST_F |157				     FW_CMD_WRITE_F |158				     FW_PTP_CMD_PORTID_V(port));159	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));160	c.u.init.sc = FW_PTP_SC_TX_TYPE;161	c.u.init.mode = cpu_to_be16(PTP_TS_NONE);162 163	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);164	if (err < 0)165		dev_err(adapter->pdev_dev,166			"PTP: %s error %d\n", __func__, -err);167 168	return err;169}170 171int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi)172{173	struct sge *s = &adapter->sge;174	struct sge_eth_rxq *receive_q =  &s->ethrxq[pi->first_qset];175	struct fw_ptp_cmd c;176	int err;177 178	memset(&c, 0, sizeof(c));179	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |180				     FW_CMD_REQUEST_F |181				     FW_CMD_WRITE_F |182				     FW_PTP_CMD_PORTID_V(pi->port_id));183 184	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));185	c.u.init.sc = FW_PTP_SC_RDRX_TYPE;186	c.u.init.txchan = pi->tx_chan;187	c.u.init.absid = cpu_to_be16(receive_q->rspq.abs_id);188 189	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);190	if (err < 0)191		dev_err(adapter->pdev_dev,192			"PTP: %s error %d\n", __func__, -err);193	return err;194}195 196/**197 * cxgb4_ptp_adjfine - Adjust frequency of PHC cycle counter198 * @ptp: ptp clock structure199 * @scaled_ppm: Desired frequency in scaled parts per billion200 *201 * Adjust the frequency of the PHC cycle counter by the indicated amount from202 * the base frequency.203 *204 * Scaled parts per million is ppm with a 16-bit binary fractional field.205 */206static int cxgb4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)207{208	struct adapter *adapter = (struct adapter *)container_of(ptp,209				   struct adapter, ptp_clock_info);210	s32 ppb = scaled_ppm_to_ppb(scaled_ppm);211	struct fw_ptp_cmd c;212	int err;213 214	memset(&c, 0, sizeof(c));215	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |216				     FW_CMD_REQUEST_F |217				     FW_CMD_WRITE_F |218				     FW_PTP_CMD_PORTID_V(0));219	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));220	c.u.ts.sc = FW_PTP_SC_ADJ_FREQ;221	c.u.ts.sign = (ppb < 0) ? 1 : 0;222	if (ppb < 0)223		ppb = -ppb;224	c.u.ts.ppb = cpu_to_be32(ppb);225 226	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);227	if (err < 0)228		dev_err(adapter->pdev_dev,229			"PTP: %s error %d\n", __func__, -err);230 231	return err;232}233 234/**235 * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock236 * @adapter: board private structure237 * @delta: Desired change in nanoseconds238 *239 * Adjust the timer by resetting the timecounter structure.240 */241static int  cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta)242{243	struct fw_ptp_cmd c;244	int err;245 246	memset(&c, 0, sizeof(c));247	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |248			     FW_CMD_REQUEST_F |249			     FW_CMD_WRITE_F |250			     FW_PTP_CMD_PORTID_V(0));251	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));252	c.u.ts.sc = FW_PTP_SC_ADJ_FTIME;253	c.u.ts.sign = (delta < 0) ? 1 : 0;254	if (delta < 0)255		delta = -delta;256	c.u.ts.tm = cpu_to_be64(delta);257 258	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);259	if (err < 0)260		dev_err(adapter->pdev_dev,261			"PTP: %s error %d\n", __func__, -err);262	return err;263}264 265/**266 * cxgb4_ptp_adjtime - Shift the time of the hardware clock267 * @ptp: ptp clock structure268 * @delta: Desired change in nanoseconds269 *270 * Adjust the timer by resetting the timecounter structure.271 */272static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)273{274	struct adapter *adapter =275		(struct adapter *)container_of(ptp, struct adapter,276					       ptp_clock_info);277	struct fw_ptp_cmd c;278	s64 sign = 1;279	int err;280 281	if (delta < 0)282		sign = -1;283 284	if (delta * sign > PTP_CLOCK_MAX_ADJTIME) {285		memset(&c, 0, sizeof(c));286		c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |287					     FW_CMD_REQUEST_F |288					     FW_CMD_WRITE_F |289					     FW_PTP_CMD_PORTID_V(0));290		c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));291		c.u.ts.sc = FW_PTP_SC_ADJ_TIME;292		c.u.ts.sign = (delta < 0) ? 1 : 0;293		if (delta < 0)294			delta = -delta;295		c.u.ts.tm = cpu_to_be64(delta);296 297		err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);298		if (err < 0)299			dev_err(adapter->pdev_dev,300				"PTP: %s error %d\n", __func__, -err);301	} else {302		err = cxgb4_ptp_fineadjtime(adapter, delta);303	}304 305	return err;306}307 308/**309 * cxgb4_ptp_gettime - Reads the current time from the hardware clock310 * @ptp: ptp clock structure311 * @ts: timespec structure to hold the current time value312 *313 * Read the timecounter and return the correct value in ns after converting314 * it into a struct timespec.315 */316static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)317{318	struct adapter *adapter = container_of(ptp, struct adapter,319					       ptp_clock_info);320	u64 ns;321 322	ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A));323	ns |= (u64)t4_read_reg(adapter,324			       T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32;325 326	/* convert to timespec*/327	*ts = ns_to_timespec64(ns);328	return 0;329}330 331/**332 *  cxgb4_ptp_settime - Set the current time on the hardware clock333 *  @ptp: ptp clock structure334 *  @ts: timespec containing the new time for the cycle counter335 *336 *  Reset value to new base value instead of the kernel337 *  wall timer value.338 */339static int cxgb4_ptp_settime(struct ptp_clock_info *ptp,340			     const struct timespec64 *ts)341{342	struct adapter *adapter = (struct adapter *)container_of(ptp,343				   struct adapter, ptp_clock_info);344	struct fw_ptp_cmd c;345	u64 ns;346	int err;347 348	memset(&c, 0, sizeof(c));349	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |350				     FW_CMD_REQUEST_F |351				     FW_CMD_WRITE_F |352				     FW_PTP_CMD_PORTID_V(0));353	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));354	c.u.ts.sc = FW_PTP_SC_SET_TIME;355 356	ns = timespec64_to_ns(ts);357	c.u.ts.tm = cpu_to_be64(ns);358 359	err =  t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);360	if (err < 0)361		dev_err(adapter->pdev_dev,362			"PTP: %s error %d\n", __func__, -err);363 364	return err;365}366 367static void cxgb4_init_ptp_timer(struct adapter *adapter)368{369	struct fw_ptp_cmd c;370	int err;371 372	memset(&c, 0, sizeof(c));373	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |374				     FW_CMD_REQUEST_F |375				     FW_CMD_WRITE_F |376				     FW_PTP_CMD_PORTID_V(0));377	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));378	c.u.scmd.sc = FW_PTP_SC_INIT_TIMER;379 380	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);381	if (err < 0)382		dev_err(adapter->pdev_dev,383			"PTP: %s error %d\n", __func__, -err);384}385 386/**387 * cxgb4_ptp_enable - enable or disable an ancillary feature388 * @ptp: ptp clock structure389 * @request: Desired resource to enable or disable390 * @on: Caller passes one to enable or zero to disable391 *392 * Enable (or disable) ancillary features of the PHC subsystem.393 * Currently, no ancillary features are supported.394 */395static int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp,396			    struct ptp_clock_request __always_unused *request,397			    int __always_unused on)398{399	return -ENOTSUPP;400}401 402static const struct ptp_clock_info cxgb4_ptp_clock_info = {403	.owner          = THIS_MODULE,404	.name           = "cxgb4_clock",405	.max_adj        = MAX_PTP_FREQ_ADJ,406	.n_alarm        = 0,407	.n_ext_ts       = 0,408	.n_per_out      = 0,409	.pps            = 0,410	.adjfine        = cxgb4_ptp_adjfine,411	.adjtime        = cxgb4_ptp_adjtime,412	.gettime64      = cxgb4_ptp_gettime,413	.settime64      = cxgb4_ptp_settime,414	.enable         = cxgb4_ptp_enable,415};416 417/**418 * cxgb4_ptp_init - initialize PTP for devices which support it419 * @adapter: board private structure420 *421 * This function performs the required steps for enabling PTP support.422 */423void cxgb4_ptp_init(struct adapter *adapter)424{425	struct timespec64 now;426	 /* no need to create a clock device if we already have one */427	if (!IS_ERR_OR_NULL(adapter->ptp_clock))428		return;429 430	adapter->ptp_tx_skb = NULL;431	adapter->ptp_clock_info = cxgb4_ptp_clock_info;432	spin_lock_init(&adapter->ptp_lock);433 434	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,435						&adapter->pdev->dev);436	if (IS_ERR_OR_NULL(adapter->ptp_clock)) {437		adapter->ptp_clock = NULL;438		dev_err(adapter->pdev_dev,439			"PTP %s Clock registration has failed\n", __func__);440		return;441	}442 443	now = ktime_to_timespec64(ktime_get_real());444	cxgb4_init_ptp_timer(adapter);445	if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) {446		ptp_clock_unregister(adapter->ptp_clock);447		adapter->ptp_clock = NULL;448	}449}450 451/**452 * cxgb4_ptp_stop - disable PTP device and stop the overflow check453 * @adapter: board private structure454 *455 * Stop the PTP support.456 */457void cxgb4_ptp_stop(struct adapter *adapter)458{459	if (adapter->ptp_tx_skb) {460		dev_kfree_skb_any(adapter->ptp_tx_skb);461		adapter->ptp_tx_skb = NULL;462	}463 464	if (adapter->ptp_clock) {465		ptp_clock_unregister(adapter->ptp_clock);466		adapter->ptp_clock = NULL;467	}468}469