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