1a4569504SAtul Gupta /* 2a4569504SAtul Gupta * cxgb4_ptp.c:Chelsio PTP support for T5/T6 3a4569504SAtul Gupta * 4a4569504SAtul Gupta * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved. 5a4569504SAtul Gupta * 6a4569504SAtul Gupta * This software is available to you under a choice of one of two 7a4569504SAtul Gupta * licenses. You may choose to be licensed under the terms of the GNU 8a4569504SAtul Gupta * General Public License (GPL) Version 2, available from the file 9a4569504SAtul Gupta * COPYING in the main directory of this source tree, or the 10a4569504SAtul Gupta * OpenIB.org BSD license below: 11a4569504SAtul Gupta * 12a4569504SAtul Gupta * Redistribution and use in source and binary forms, with or 13a4569504SAtul Gupta * without modification, are permitted provided that the following 14a4569504SAtul Gupta * conditions are met: 15a4569504SAtul Gupta * 16a4569504SAtul Gupta * - Redistributions of source code must retain the above 17a4569504SAtul Gupta * copyright notice, this list of conditions and the following 18a4569504SAtul Gupta * disclaimer. 19a4569504SAtul Gupta * 20a4569504SAtul Gupta * - Redistributions in binary form must reproduce the above 21a4569504SAtul Gupta * copyright notice, this list of conditions and the following 22a4569504SAtul Gupta * disclaimer in the documentation and/or other materials 23a4569504SAtul Gupta * provided with the distribution. 24a4569504SAtul Gupta * 25a4569504SAtul Gupta * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26a4569504SAtul Gupta * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27a4569504SAtul Gupta * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28a4569504SAtul Gupta * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29a4569504SAtul Gupta * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30a4569504SAtul Gupta * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31a4569504SAtul Gupta * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32a4569504SAtul Gupta * SOFTWARE. 33a4569504SAtul Gupta * 34a4569504SAtul Gupta * Written by: Atul Gupta (atul.gupta@chelsio.com) 35a4569504SAtul Gupta */ 36a4569504SAtul Gupta 37a4569504SAtul Gupta #include <linux/module.h> 38a4569504SAtul Gupta #include <linux/net_tstamp.h> 39a4569504SAtul Gupta #include <linux/skbuff.h> 40a4569504SAtul Gupta #include <linux/netdevice.h> 41a4569504SAtul Gupta #include <linux/pps_kernel.h> 42a4569504SAtul Gupta #include <linux/ptp_clock_kernel.h> 43a4569504SAtul Gupta #include <linux/ptp_classify.h> 44a4569504SAtul Gupta #include <linux/udp.h> 45a4569504SAtul Gupta 46a4569504SAtul Gupta #include "cxgb4.h" 47a4569504SAtul Gupta #include "t4_hw.h" 48a4569504SAtul Gupta #include "t4_regs.h" 49a4569504SAtul Gupta #include "t4_msg.h" 50a4569504SAtul Gupta #include "t4fw_api.h" 51a4569504SAtul Gupta #include "cxgb4_ptp.h" 52a4569504SAtul Gupta 53a4569504SAtul Gupta /** 54a4569504SAtul Gupta * cxgb4_ptp_is_ptp_tx - determine whether TX packet is PTP or not 55a4569504SAtul Gupta * @skb: skb of outgoing ptp request 56a4569504SAtul Gupta * 57a4569504SAtul Gupta */ 58a4569504SAtul Gupta bool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb) 59a4569504SAtul Gupta { 60a4569504SAtul Gupta struct udphdr *uh; 61a4569504SAtul Gupta 62a4569504SAtul Gupta uh = udp_hdr(skb); 63a4569504SAtul Gupta return skb->len >= PTP_MIN_LENGTH && 64a4569504SAtul Gupta skb->len <= PTP_IN_TRANSMIT_PACKET_MAXNUM && 65a4569504SAtul Gupta likely(skb->protocol == htons(ETH_P_IP)) && 66a4569504SAtul Gupta ip_hdr(skb)->protocol == IPPROTO_UDP && 67a4569504SAtul Gupta uh->dest == htons(PTP_EVENT_PORT); 68a4569504SAtul Gupta } 69a4569504SAtul Gupta 70a4569504SAtul Gupta bool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev) 71a4569504SAtul Gupta { 72a4569504SAtul Gupta struct port_info *pi; 73a4569504SAtul Gupta 74a4569504SAtul Gupta pi = netdev_priv(dev); 75a4569504SAtul Gupta return (pi->ptp_enable && cxgb4_xmit_with_hwtstamp(skb) && 76a4569504SAtul Gupta cxgb4_ptp_is_ptp_tx(skb)); 77a4569504SAtul Gupta } 78a4569504SAtul Gupta 79a4569504SAtul Gupta /** 80a4569504SAtul Gupta * cxgb4_ptp_is_ptp_rx - determine whether RX packet is PTP or not 81a4569504SAtul Gupta * @skb: skb of incoming ptp request 82a4569504SAtul Gupta * 83a4569504SAtul Gupta */ 84a4569504SAtul Gupta bool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb) 85a4569504SAtul Gupta { 86a4569504SAtul Gupta struct udphdr *uh = (struct udphdr *)(skb->data + ETH_HLEN + 87a4569504SAtul Gupta IPV4_HLEN(skb->data)); 88a4569504SAtul Gupta 89a4569504SAtul Gupta return uh->dest == htons(PTP_EVENT_PORT) && 90a4569504SAtul Gupta uh->source == htons(PTP_EVENT_PORT); 91a4569504SAtul Gupta } 92a4569504SAtul Gupta 93a4569504SAtul Gupta /** 94a4569504SAtul Gupta * cxgb4_ptp_read_hwstamp - read timestamp for TX event PTP message 95a4569504SAtul Gupta * @adapter: board private structure 96a4569504SAtul Gupta * @pi: port private structure 97a4569504SAtul Gupta * 98a4569504SAtul Gupta */ 99a4569504SAtul Gupta void cxgb4_ptp_read_hwstamp(struct adapter *adapter, struct port_info *pi) 100a4569504SAtul Gupta { 101a4569504SAtul Gupta struct skb_shared_hwtstamps *skb_ts = NULL; 102a4569504SAtul Gupta u64 tx_ts; 103a4569504SAtul Gupta 104a4569504SAtul Gupta skb_ts = skb_hwtstamps(adapter->ptp_tx_skb); 105a4569504SAtul Gupta 106a4569504SAtul Gupta tx_ts = t4_read_reg(adapter, 107a4569504SAtul Gupta T5_PORT_REG(pi->port_id, MAC_PORT_TX_TS_VAL_LO)); 108a4569504SAtul Gupta 109a4569504SAtul Gupta tx_ts |= (u64)t4_read_reg(adapter, 110a4569504SAtul Gupta T5_PORT_REG(pi->port_id, 111a4569504SAtul Gupta MAC_PORT_TX_TS_VAL_HI)) << 32; 112a4569504SAtul Gupta skb_ts->hwtstamp = ns_to_ktime(tx_ts); 113a4569504SAtul Gupta skb_tstamp_tx(adapter->ptp_tx_skb, skb_ts); 114a4569504SAtul Gupta dev_kfree_skb_any(adapter->ptp_tx_skb); 115a4569504SAtul Gupta spin_lock(&adapter->ptp_lock); 116a4569504SAtul Gupta adapter->ptp_tx_skb = NULL; 117a4569504SAtul Gupta spin_unlock(&adapter->ptp_lock); 118a4569504SAtul Gupta } 119a4569504SAtul Gupta 120a4569504SAtul Gupta /** 121a4569504SAtul Gupta * cxgb4_ptprx_timestamping - Enable Timestamp for RX PTP event message 122a4569504SAtul Gupta * @pi: port private structure 123a4569504SAtul Gupta * @port: pot number 124a4569504SAtul Gupta * @mode: RX mode 125a4569504SAtul Gupta * 126a4569504SAtul Gupta */ 127a4569504SAtul Gupta int cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode) 128a4569504SAtul Gupta { 129a4569504SAtul Gupta struct adapter *adapter = pi->adapter; 130a4569504SAtul Gupta struct fw_ptp_cmd c; 131a4569504SAtul Gupta int err; 132a4569504SAtul Gupta 133a4569504SAtul Gupta memset(&c, 0, sizeof(c)); 134a4569504SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 135a4569504SAtul Gupta FW_CMD_REQUEST_F | 136a4569504SAtul Gupta FW_CMD_WRITE_F | 137a4569504SAtul Gupta FW_PTP_CMD_PORTID_V(port)); 138a4569504SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 139a4569504SAtul Gupta c.u.init.sc = FW_PTP_SC_RXTIME_STAMP; 140a4569504SAtul Gupta c.u.init.mode = cpu_to_be16(mode); 141a4569504SAtul Gupta 142a4569504SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 143a4569504SAtul Gupta if (err < 0) 144a4569504SAtul Gupta dev_err(adapter->pdev_dev, 145a4569504SAtul Gupta "PTP: %s error %d\n", __func__, -err); 146a4569504SAtul Gupta return err; 147a4569504SAtul Gupta } 148a4569504SAtul Gupta 149a4569504SAtul Gupta int cxgb4_ptp_txtype(struct adapter *adapter, u8 port) 150a4569504SAtul Gupta { 151a4569504SAtul Gupta struct fw_ptp_cmd c; 152a4569504SAtul Gupta int err; 153a4569504SAtul Gupta 154a4569504SAtul Gupta memset(&c, 0, sizeof(c)); 155a4569504SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 156a4569504SAtul Gupta FW_CMD_REQUEST_F | 157a4569504SAtul Gupta FW_CMD_WRITE_F | 158a4569504SAtul Gupta FW_PTP_CMD_PORTID_V(port)); 159a4569504SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 160a4569504SAtul Gupta c.u.init.sc = FW_PTP_SC_TX_TYPE; 161a4569504SAtul Gupta c.u.init.mode = cpu_to_be16(PTP_TS_NONE); 162a4569504SAtul Gupta 163a4569504SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 164a4569504SAtul Gupta if (err < 0) 165a4569504SAtul Gupta dev_err(adapter->pdev_dev, 166a4569504SAtul Gupta "PTP: %s error %d\n", __func__, -err); 167a4569504SAtul Gupta 168a4569504SAtul Gupta return err; 169a4569504SAtul Gupta } 170a4569504SAtul Gupta 171a4569504SAtul Gupta int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi) 172a4569504SAtul Gupta { 173a4569504SAtul Gupta struct sge *s = &adapter->sge; 174a4569504SAtul Gupta struct sge_eth_rxq *receive_q = &s->ethrxq[pi->first_qset]; 175a4569504SAtul Gupta struct fw_ptp_cmd c; 176a4569504SAtul Gupta int err; 177a4569504SAtul Gupta 178a4569504SAtul Gupta memset(&c, 0, sizeof(c)); 179a4569504SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 180a4569504SAtul Gupta FW_CMD_REQUEST_F | 181a4569504SAtul Gupta FW_CMD_WRITE_F | 182a4569504SAtul Gupta FW_PTP_CMD_PORTID_V(pi->port_id)); 183a4569504SAtul Gupta 184a4569504SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 185a4569504SAtul Gupta c.u.init.sc = FW_PTP_SC_RDRX_TYPE; 186a4569504SAtul Gupta c.u.init.txchan = pi->tx_chan; 187a4569504SAtul Gupta c.u.init.absid = cpu_to_be16(receive_q->rspq.abs_id); 188a4569504SAtul Gupta 189a4569504SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 190a4569504SAtul Gupta if (err < 0) 191a4569504SAtul Gupta dev_err(adapter->pdev_dev, 192a4569504SAtul Gupta "PTP: %s error %d\n", __func__, -err); 193a4569504SAtul Gupta return err; 194a4569504SAtul Gupta } 1959c33e420SAtul Gupta 1969c33e420SAtul Gupta /** 19729bbf5d7SRahul Lakkireddy * cxgb4_ptp_adjfreq - Adjust frequency of PHC cycle counter 1989c33e420SAtul Gupta * @ptp: ptp clock structure 1999c33e420SAtul Gupta * @ppb: Desired frequency change in parts per billion 2009c33e420SAtul Gupta * 2019c33e420SAtul Gupta * Adjust the frequency of the PHC cycle counter by the indicated ppb from 2029c33e420SAtul Gupta * the base frequency. 2039c33e420SAtul Gupta */ 2049c33e420SAtul Gupta static int cxgb4_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 2059c33e420SAtul Gupta { 2069c33e420SAtul Gupta struct adapter *adapter = (struct adapter *)container_of(ptp, 2079c33e420SAtul Gupta struct adapter, ptp_clock_info); 2089c33e420SAtul Gupta struct fw_ptp_cmd c; 2099c33e420SAtul Gupta int err; 2109c33e420SAtul Gupta 2119c33e420SAtul Gupta memset(&c, 0, sizeof(c)); 2129c33e420SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2139c33e420SAtul Gupta FW_CMD_REQUEST_F | 2149c33e420SAtul Gupta FW_CMD_WRITE_F | 2159c33e420SAtul Gupta FW_PTP_CMD_PORTID_V(0)); 2169c33e420SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2179c33e420SAtul Gupta c.u.ts.sc = FW_PTP_SC_ADJ_FREQ; 2189c33e420SAtul Gupta c.u.ts.sign = (ppb < 0) ? 1 : 0; 2199c33e420SAtul Gupta if (ppb < 0) 2209c33e420SAtul Gupta ppb = -ppb; 2219c33e420SAtul Gupta c.u.ts.ppb = cpu_to_be32(ppb); 2229c33e420SAtul Gupta 2239c33e420SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2249c33e420SAtul Gupta if (err < 0) 2259c33e420SAtul Gupta dev_err(adapter->pdev_dev, 2269c33e420SAtul Gupta "PTP: %s error %d\n", __func__, -err); 2279c33e420SAtul Gupta 2289c33e420SAtul Gupta return err; 2299c33e420SAtul Gupta } 2309c33e420SAtul Gupta 2319c33e420SAtul Gupta /** 2329c33e420SAtul Gupta * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock 23329bbf5d7SRahul Lakkireddy * @adapter: board private structure 2349c33e420SAtul Gupta * @delta: Desired change in nanoseconds 2359c33e420SAtul Gupta * 2369c33e420SAtul Gupta * Adjust the timer by resetting the timecounter structure. 2379c33e420SAtul Gupta */ 2389c33e420SAtul Gupta static int cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta) 2399c33e420SAtul Gupta { 2409c33e420SAtul Gupta struct fw_ptp_cmd c; 2419c33e420SAtul Gupta int err; 2429c33e420SAtul Gupta 2439c33e420SAtul Gupta memset(&c, 0, sizeof(c)); 2449c33e420SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2459c33e420SAtul Gupta FW_CMD_REQUEST_F | 2469c33e420SAtul Gupta FW_CMD_WRITE_F | 2479c33e420SAtul Gupta FW_PTP_CMD_PORTID_V(0)); 2489c33e420SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2499c33e420SAtul Gupta c.u.ts.sc = FW_PTP_SC_ADJ_FTIME; 25050e0d28dSRaju Rangoju c.u.ts.sign = (delta < 0) ? 1 : 0; 25150e0d28dSRaju Rangoju if (delta < 0) 25250e0d28dSRaju Rangoju delta = -delta; 2539c33e420SAtul Gupta c.u.ts.tm = cpu_to_be64(delta); 2549c33e420SAtul Gupta 2559c33e420SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2569c33e420SAtul Gupta if (err < 0) 2579c33e420SAtul Gupta dev_err(adapter->pdev_dev, 2589c33e420SAtul Gupta "PTP: %s error %d\n", __func__, -err); 2599c33e420SAtul Gupta return err; 2609c33e420SAtul Gupta } 2619c33e420SAtul Gupta 2629c33e420SAtul Gupta /** 2639c33e420SAtul Gupta * cxgb4_ptp_adjtime - Shift the time of the hardware clock 2649c33e420SAtul Gupta * @ptp: ptp clock structure 2659c33e420SAtul Gupta * @delta: Desired change in nanoseconds 2669c33e420SAtul Gupta * 2679c33e420SAtul Gupta * Adjust the timer by resetting the timecounter structure. 2689c33e420SAtul Gupta */ 2699c33e420SAtul Gupta static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 2709c33e420SAtul Gupta { 2719c33e420SAtul Gupta struct adapter *adapter = 2729c33e420SAtul Gupta (struct adapter *)container_of(ptp, struct adapter, 2739c33e420SAtul Gupta ptp_clock_info); 2749c33e420SAtul Gupta struct fw_ptp_cmd c; 2759c33e420SAtul Gupta s64 sign = 1; 2769c33e420SAtul Gupta int err; 2779c33e420SAtul Gupta 2789c33e420SAtul Gupta if (delta < 0) 2799c33e420SAtul Gupta sign = -1; 2809c33e420SAtul Gupta 2819c33e420SAtul Gupta if (delta * sign > PTP_CLOCK_MAX_ADJTIME) { 2829c33e420SAtul Gupta memset(&c, 0, sizeof(c)); 2839c33e420SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2849c33e420SAtul Gupta FW_CMD_REQUEST_F | 2859c33e420SAtul Gupta FW_CMD_WRITE_F | 2869c33e420SAtul Gupta FW_PTP_CMD_PORTID_V(0)); 2879c33e420SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2889c33e420SAtul Gupta c.u.ts.sc = FW_PTP_SC_ADJ_TIME; 2899c33e420SAtul Gupta c.u.ts.sign = (delta < 0) ? 1 : 0; 2909c33e420SAtul Gupta if (delta < 0) 2919c33e420SAtul Gupta delta = -delta; 2929c33e420SAtul Gupta c.u.ts.tm = cpu_to_be64(delta); 2939c33e420SAtul Gupta 2949c33e420SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2959c33e420SAtul Gupta if (err < 0) 2969c33e420SAtul Gupta dev_err(adapter->pdev_dev, 2979c33e420SAtul Gupta "PTP: %s error %d\n", __func__, -err); 2989c33e420SAtul Gupta } else { 2999c33e420SAtul Gupta err = cxgb4_ptp_fineadjtime(adapter, delta); 3009c33e420SAtul Gupta } 3019c33e420SAtul Gupta 3029c33e420SAtul Gupta return err; 3039c33e420SAtul Gupta } 3049c33e420SAtul Gupta 3059c33e420SAtul Gupta /** 3069c33e420SAtul Gupta * cxgb4_ptp_gettime - Reads the current time from the hardware clock 3079c33e420SAtul Gupta * @ptp: ptp clock structure 3089c33e420SAtul Gupta * @ts: timespec structure to hold the current time value 3099c33e420SAtul Gupta * 3109c33e420SAtul Gupta * Read the timecounter and return the correct value in ns after converting 3119c33e420SAtul Gupta * it into a struct timespec. 3129c33e420SAtul Gupta */ 3139c33e420SAtul Gupta static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 3149c33e420SAtul Gupta { 315bd019427SRahul Lakkireddy struct adapter *adapter = container_of(ptp, struct adapter, 316bd019427SRahul Lakkireddy ptp_clock_info); 3179c33e420SAtul Gupta u64 ns; 3189c33e420SAtul Gupta 319bd019427SRahul Lakkireddy ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A)); 320bd019427SRahul Lakkireddy ns |= (u64)t4_read_reg(adapter, 321bd019427SRahul Lakkireddy T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32; 3229c33e420SAtul Gupta 3239c33e420SAtul Gupta /* convert to timespec*/ 3249c33e420SAtul Gupta *ts = ns_to_timespec64(ns); 325bd019427SRahul Lakkireddy return 0; 3269c33e420SAtul Gupta } 3279c33e420SAtul Gupta 3289c33e420SAtul Gupta /** 3299c33e420SAtul Gupta * cxgb4_ptp_settime - Set the current time on the hardware clock 3309c33e420SAtul Gupta * @ptp: ptp clock structure 3319c33e420SAtul Gupta * @ts: timespec containing the new time for the cycle counter 3329c33e420SAtul Gupta * 3339c33e420SAtul Gupta * Reset value to new base value instead of the kernel 3349c33e420SAtul Gupta * wall timer value. 3359c33e420SAtul Gupta */ 3369c33e420SAtul Gupta static int cxgb4_ptp_settime(struct ptp_clock_info *ptp, 3379c33e420SAtul Gupta const struct timespec64 *ts) 3389c33e420SAtul Gupta { 3399c33e420SAtul Gupta struct adapter *adapter = (struct adapter *)container_of(ptp, 3409c33e420SAtul Gupta struct adapter, ptp_clock_info); 3419c33e420SAtul Gupta struct fw_ptp_cmd c; 3429c33e420SAtul Gupta u64 ns; 3439c33e420SAtul Gupta int err; 3449c33e420SAtul Gupta 3459c33e420SAtul Gupta memset(&c, 0, sizeof(c)); 3469c33e420SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 3479c33e420SAtul Gupta FW_CMD_REQUEST_F | 3489c33e420SAtul Gupta FW_CMD_WRITE_F | 3499c33e420SAtul Gupta FW_PTP_CMD_PORTID_V(0)); 3509c33e420SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 3519c33e420SAtul Gupta c.u.ts.sc = FW_PTP_SC_SET_TIME; 3529c33e420SAtul Gupta 3539c33e420SAtul Gupta ns = timespec64_to_ns(ts); 3549c33e420SAtul Gupta c.u.ts.tm = cpu_to_be64(ns); 3559c33e420SAtul Gupta 3569c33e420SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 3579c33e420SAtul Gupta if (err < 0) 3589c33e420SAtul Gupta dev_err(adapter->pdev_dev, 3599c33e420SAtul Gupta "PTP: %s error %d\n", __func__, -err); 3609c33e420SAtul Gupta 3619c33e420SAtul Gupta return err; 3629c33e420SAtul Gupta } 3639c33e420SAtul Gupta 3649c33e420SAtul Gupta static void cxgb4_init_ptp_timer(struct adapter *adapter) 3659c33e420SAtul Gupta { 3669c33e420SAtul Gupta struct fw_ptp_cmd c; 3679c33e420SAtul Gupta int err; 3689c33e420SAtul Gupta 3699c33e420SAtul Gupta memset(&c, 0, sizeof(c)); 3709c33e420SAtul Gupta c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 3719c33e420SAtul Gupta FW_CMD_REQUEST_F | 3729c33e420SAtul Gupta FW_CMD_WRITE_F | 3739c33e420SAtul Gupta FW_PTP_CMD_PORTID_V(0)); 3749c33e420SAtul Gupta c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 3759c33e420SAtul Gupta c.u.scmd.sc = FW_PTP_SC_INIT_TIMER; 3769c33e420SAtul Gupta 3779c33e420SAtul Gupta err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 3789c33e420SAtul Gupta if (err < 0) 3799c33e420SAtul Gupta dev_err(adapter->pdev_dev, 3809c33e420SAtul Gupta "PTP: %s error %d\n", __func__, -err); 3819c33e420SAtul Gupta } 3829c33e420SAtul Gupta 3839c33e420SAtul Gupta /** 3849c33e420SAtul Gupta * cxgb4_ptp_enable - enable or disable an ancillary feature 3859c33e420SAtul Gupta * @ptp: ptp clock structure 3869c33e420SAtul Gupta * @request: Desired resource to enable or disable 3879c33e420SAtul Gupta * @on: Caller passes one to enable or zero to disable 3889c33e420SAtul Gupta * 3899c33e420SAtul Gupta * Enable (or disable) ancillary features of the PHC subsystem. 3909c33e420SAtul Gupta * Currently, no ancillary features are supported. 3919c33e420SAtul Gupta */ 3929c33e420SAtul Gupta static int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp, 3939c33e420SAtul Gupta struct ptp_clock_request __always_unused *request, 3949c33e420SAtul Gupta int __always_unused on) 3959c33e420SAtul Gupta { 3969c33e420SAtul Gupta return -ENOTSUPP; 3979c33e420SAtul Gupta } 3989c33e420SAtul Gupta 3999c33e420SAtul Gupta static const struct ptp_clock_info cxgb4_ptp_clock_info = { 4009c33e420SAtul Gupta .owner = THIS_MODULE, 4019c33e420SAtul Gupta .name = "cxgb4_clock", 4029c33e420SAtul Gupta .max_adj = MAX_PTP_FREQ_ADJ, 4039c33e420SAtul Gupta .n_alarm = 0, 4049c33e420SAtul Gupta .n_ext_ts = 0, 4059c33e420SAtul Gupta .n_per_out = 0, 4069c33e420SAtul Gupta .pps = 0, 4079c33e420SAtul Gupta .adjfreq = cxgb4_ptp_adjfreq, 4089c33e420SAtul Gupta .adjtime = cxgb4_ptp_adjtime, 4099c33e420SAtul Gupta .gettime64 = cxgb4_ptp_gettime, 4109c33e420SAtul Gupta .settime64 = cxgb4_ptp_settime, 4119c33e420SAtul Gupta .enable = cxgb4_ptp_enable, 4129c33e420SAtul Gupta }; 4139c33e420SAtul Gupta 4149c33e420SAtul Gupta /** 4159c33e420SAtul Gupta * cxgb4_ptp_init - initialize PTP for devices which support it 4169c33e420SAtul Gupta * @adapter: board private structure 4179c33e420SAtul Gupta * 4189c33e420SAtul Gupta * This function performs the required steps for enabling PTP support. 4199c33e420SAtul Gupta */ 4209c33e420SAtul Gupta void cxgb4_ptp_init(struct adapter *adapter) 4219c33e420SAtul Gupta { 4229c33e420SAtul Gupta struct timespec64 now; 4239c33e420SAtul Gupta /* no need to create a clock device if we already have one */ 4249c33e420SAtul Gupta if (!IS_ERR_OR_NULL(adapter->ptp_clock)) 4259c33e420SAtul Gupta return; 4269c33e420SAtul Gupta 4279c33e420SAtul Gupta adapter->ptp_tx_skb = NULL; 4289c33e420SAtul Gupta adapter->ptp_clock_info = cxgb4_ptp_clock_info; 4299c33e420SAtul Gupta spin_lock_init(&adapter->ptp_lock); 4309c33e420SAtul Gupta 4319c33e420SAtul Gupta adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info, 4329c33e420SAtul Gupta &adapter->pdev->dev); 43340fbbce0SGanesh Goudar if (IS_ERR_OR_NULL(adapter->ptp_clock)) { 43440fbbce0SGanesh Goudar adapter->ptp_clock = NULL; 4359c33e420SAtul Gupta dev_err(adapter->pdev_dev, 4369c33e420SAtul Gupta "PTP %s Clock registration has failed\n", __func__); 4379c33e420SAtul Gupta return; 4389c33e420SAtul Gupta } 4399c33e420SAtul Gupta 4409c33e420SAtul Gupta now = ktime_to_timespec64(ktime_get_real()); 4419c33e420SAtul Gupta cxgb4_init_ptp_timer(adapter); 4429c33e420SAtul Gupta if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) { 4439c33e420SAtul Gupta ptp_clock_unregister(adapter->ptp_clock); 4449c33e420SAtul Gupta adapter->ptp_clock = NULL; 4459c33e420SAtul Gupta } 4469c33e420SAtul Gupta } 4479c33e420SAtul Gupta 4489c33e420SAtul Gupta /** 449*e0333b1bSYang Shen * cxgb4_ptp_stop - disable PTP device and stop the overflow check 4509c33e420SAtul Gupta * @adapter: board private structure 4519c33e420SAtul Gupta * 4529c33e420SAtul Gupta * Stop the PTP support. 4539c33e420SAtul Gupta */ 4549c33e420SAtul Gupta void cxgb4_ptp_stop(struct adapter *adapter) 4559c33e420SAtul Gupta { 4569c33e420SAtul Gupta if (adapter->ptp_tx_skb) { 4579c33e420SAtul Gupta dev_kfree_skb_any(adapter->ptp_tx_skb); 4589c33e420SAtul Gupta adapter->ptp_tx_skb = NULL; 4599c33e420SAtul Gupta } 4609c33e420SAtul Gupta 4619c33e420SAtul Gupta if (adapter->ptp_clock) { 4629c33e420SAtul Gupta ptp_clock_unregister(adapter->ptp_clock); 4639c33e420SAtul Gupta adapter->ptp_clock = NULL; 4649c33e420SAtul Gupta } 4659c33e420SAtul Gupta } 466