18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * cxgb4_ptp.c:Chelsio PTP support for T5/T6 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Written by: Atul Gupta (atul.gupta@chelsio.com) 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 398c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 408c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 418c2ecf20Sopenharmony_ci#include <linux/pps_kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 438c2ecf20Sopenharmony_ci#include <linux/ptp_classify.h> 448c2ecf20Sopenharmony_ci#include <linux/udp.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include "cxgb4.h" 478c2ecf20Sopenharmony_ci#include "t4_hw.h" 488c2ecf20Sopenharmony_ci#include "t4_regs.h" 498c2ecf20Sopenharmony_ci#include "t4_msg.h" 508c2ecf20Sopenharmony_ci#include "t4fw_api.h" 518c2ecf20Sopenharmony_ci#include "cxgb4_ptp.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * cxgb4_ptp_is_ptp_tx - determine whether TX packet is PTP or not 558c2ecf20Sopenharmony_ci * @skb: skb of outgoing ptp request 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cibool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct udphdr *uh; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci uh = udp_hdr(skb); 638c2ecf20Sopenharmony_ci return skb->len >= PTP_MIN_LENGTH && 648c2ecf20Sopenharmony_ci skb->len <= PTP_IN_TRANSMIT_PACKET_MAXNUM && 658c2ecf20Sopenharmony_ci likely(skb->protocol == htons(ETH_P_IP)) && 668c2ecf20Sopenharmony_ci ip_hdr(skb)->protocol == IPPROTO_UDP && 678c2ecf20Sopenharmony_ci uh->dest == htons(PTP_EVENT_PORT); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cibool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct port_info *pi; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci pi = netdev_priv(dev); 758c2ecf20Sopenharmony_ci return (pi->ptp_enable && cxgb4_xmit_with_hwtstamp(skb) && 768c2ecf20Sopenharmony_ci cxgb4_ptp_is_ptp_tx(skb)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * cxgb4_ptp_is_ptp_rx - determine whether RX packet is PTP or not 818c2ecf20Sopenharmony_ci * @skb: skb of incoming ptp request 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cibool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct udphdr *uh = (struct udphdr *)(skb->data + ETH_HLEN + 878c2ecf20Sopenharmony_ci IPV4_HLEN(skb->data)); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return uh->dest == htons(PTP_EVENT_PORT) && 908c2ecf20Sopenharmony_ci uh->source == htons(PTP_EVENT_PORT); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * cxgb4_ptp_read_hwstamp - read timestamp for TX event PTP message 958c2ecf20Sopenharmony_ci * @adapter: board private structure 968c2ecf20Sopenharmony_ci * @pi: port private structure 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_civoid cxgb4_ptp_read_hwstamp(struct adapter *adapter, struct port_info *pi) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *skb_ts = NULL; 1028c2ecf20Sopenharmony_ci u64 tx_ts; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci skb_ts = skb_hwtstamps(adapter->ptp_tx_skb); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci tx_ts = t4_read_reg(adapter, 1078c2ecf20Sopenharmony_ci T5_PORT_REG(pi->port_id, MAC_PORT_TX_TS_VAL_LO)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci tx_ts |= (u64)t4_read_reg(adapter, 1108c2ecf20Sopenharmony_ci T5_PORT_REG(pi->port_id, 1118c2ecf20Sopenharmony_ci MAC_PORT_TX_TS_VAL_HI)) << 32; 1128c2ecf20Sopenharmony_ci skb_ts->hwtstamp = ns_to_ktime(tx_ts); 1138c2ecf20Sopenharmony_ci skb_tstamp_tx(adapter->ptp_tx_skb, skb_ts); 1148c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 1158c2ecf20Sopenharmony_ci spin_lock(&adapter->ptp_lock); 1168c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 1178c2ecf20Sopenharmony_ci spin_unlock(&adapter->ptp_lock); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * cxgb4_ptprx_timestamping - Enable Timestamp for RX PTP event message 1228c2ecf20Sopenharmony_ci * @pi: port private structure 1238c2ecf20Sopenharmony_ci * @port: pot number 1248c2ecf20Sopenharmony_ci * @mode: RX mode 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ciint cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 1308c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 1318c2ecf20Sopenharmony_ci int err; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 1348c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 1358c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 1368c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 1378c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(port)); 1388c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 1398c2ecf20Sopenharmony_ci c.u.init.sc = FW_PTP_SC_RXTIME_STAMP; 1408c2ecf20Sopenharmony_ci c.u.init.mode = cpu_to_be16(mode); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 1438c2ecf20Sopenharmony_ci if (err < 0) 1448c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 1458c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 1468c2ecf20Sopenharmony_ci return err; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciint cxgb4_ptp_txtype(struct adapter *adapter, u8 port) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 1528c2ecf20Sopenharmony_ci int err; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 1558c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 1568c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 1578c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 1588c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(port)); 1598c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 1608c2ecf20Sopenharmony_ci c.u.init.sc = FW_PTP_SC_TX_TYPE; 1618c2ecf20Sopenharmony_ci c.u.init.mode = cpu_to_be16(PTP_TS_NONE); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 1648c2ecf20Sopenharmony_ci if (err < 0) 1658c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 1668c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return err; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 1748c2ecf20Sopenharmony_ci struct sge_eth_rxq *receive_q = &s->ethrxq[pi->first_qset]; 1758c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 1768c2ecf20Sopenharmony_ci int err; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 1798c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 1808c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 1818c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 1828c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(pi->port_id)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 1858c2ecf20Sopenharmony_ci c.u.init.sc = FW_PTP_SC_RDRX_TYPE; 1868c2ecf20Sopenharmony_ci c.u.init.txchan = pi->tx_chan; 1878c2ecf20Sopenharmony_ci c.u.init.absid = cpu_to_be16(receive_q->rspq.abs_id); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 1908c2ecf20Sopenharmony_ci if (err < 0) 1918c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 1928c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 1938c2ecf20Sopenharmony_ci return err; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * cxgb4_ptp_adjfreq - Adjust frequency of PHC cycle counter 1988c2ecf20Sopenharmony_ci * @ptp: ptp clock structure 1998c2ecf20Sopenharmony_ci * @ppb: Desired frequency change in parts per billion 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * Adjust the frequency of the PHC cycle counter by the indicated ppb from 2028c2ecf20Sopenharmony_ci * the base frequency. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic int cxgb4_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct adapter *adapter = (struct adapter *)container_of(ptp, 2078c2ecf20Sopenharmony_ci struct adapter, ptp_clock_info); 2088c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 2098c2ecf20Sopenharmony_ci int err; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 2128c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2138c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 2148c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 2158c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(0)); 2168c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2178c2ecf20Sopenharmony_ci c.u.ts.sc = FW_PTP_SC_ADJ_FREQ; 2188c2ecf20Sopenharmony_ci c.u.ts.sign = (ppb < 0) ? 1 : 0; 2198c2ecf20Sopenharmony_ci if (ppb < 0) 2208c2ecf20Sopenharmony_ci ppb = -ppb; 2218c2ecf20Sopenharmony_ci c.u.ts.ppb = cpu_to_be32(ppb); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2248c2ecf20Sopenharmony_ci if (err < 0) 2258c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 2268c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return err; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock 2338c2ecf20Sopenharmony_ci * @adapter: board private structure 2348c2ecf20Sopenharmony_ci * @delta: Desired change in nanoseconds 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * Adjust the timer by resetting the timecounter structure. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_cistatic int cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 2418c2ecf20Sopenharmony_ci int err; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 2448c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2458c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 2468c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 2478c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(0)); 2488c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2498c2ecf20Sopenharmony_ci c.u.ts.sc = FW_PTP_SC_ADJ_FTIME; 2508c2ecf20Sopenharmony_ci c.u.ts.sign = (delta < 0) ? 1 : 0; 2518c2ecf20Sopenharmony_ci if (delta < 0) 2528c2ecf20Sopenharmony_ci delta = -delta; 2538c2ecf20Sopenharmony_ci c.u.ts.tm = cpu_to_be64(delta); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2568c2ecf20Sopenharmony_ci if (err < 0) 2578c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 2588c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 2598c2ecf20Sopenharmony_ci return err; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * cxgb4_ptp_adjtime - Shift the time of the hardware clock 2648c2ecf20Sopenharmony_ci * @ptp: ptp clock structure 2658c2ecf20Sopenharmony_ci * @delta: Desired change in nanoseconds 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * Adjust the timer by resetting the timecounter structure. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_cistatic int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct adapter *adapter = 2728c2ecf20Sopenharmony_ci (struct adapter *)container_of(ptp, struct adapter, 2738c2ecf20Sopenharmony_ci ptp_clock_info); 2748c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 2758c2ecf20Sopenharmony_ci s64 sign = 1; 2768c2ecf20Sopenharmony_ci int err; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (delta < 0) 2798c2ecf20Sopenharmony_ci sign = -1; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (delta * sign > PTP_CLOCK_MAX_ADJTIME) { 2828c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 2838c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 2848c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 2858c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 2868c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(0)); 2878c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 2888c2ecf20Sopenharmony_ci c.u.ts.sc = FW_PTP_SC_ADJ_TIME; 2898c2ecf20Sopenharmony_ci c.u.ts.sign = (delta < 0) ? 1 : 0; 2908c2ecf20Sopenharmony_ci if (delta < 0) 2918c2ecf20Sopenharmony_ci delta = -delta; 2928c2ecf20Sopenharmony_ci c.u.ts.tm = cpu_to_be64(delta); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 2958c2ecf20Sopenharmony_ci if (err < 0) 2968c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 2978c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci err = cxgb4_ptp_fineadjtime(adapter, delta); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return err; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * cxgb4_ptp_gettime - Reads the current time from the hardware clock 3078c2ecf20Sopenharmony_ci * @ptp: ptp clock structure 3088c2ecf20Sopenharmony_ci * @ts: timespec structure to hold the current time value 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci * Read the timecounter and return the correct value in ns after converting 3118c2ecf20Sopenharmony_ci * it into a struct timespec. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct adapter *adapter = container_of(ptp, struct adapter, 3168c2ecf20Sopenharmony_ci ptp_clock_info); 3178c2ecf20Sopenharmony_ci u64 ns; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A)); 3208c2ecf20Sopenharmony_ci ns |= (u64)t4_read_reg(adapter, 3218c2ecf20Sopenharmony_ci T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* convert to timespec*/ 3248c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/** 3298c2ecf20Sopenharmony_ci * cxgb4_ptp_settime - Set the current time on the hardware clock 3308c2ecf20Sopenharmony_ci * @ptp: ptp clock structure 3318c2ecf20Sopenharmony_ci * @ts: timespec containing the new time for the cycle counter 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * Reset value to new base value instead of the kernel 3348c2ecf20Sopenharmony_ci * wall timer value. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic int cxgb4_ptp_settime(struct ptp_clock_info *ptp, 3378c2ecf20Sopenharmony_ci const struct timespec64 *ts) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct adapter *adapter = (struct adapter *)container_of(ptp, 3408c2ecf20Sopenharmony_ci struct adapter, ptp_clock_info); 3418c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 3428c2ecf20Sopenharmony_ci u64 ns; 3438c2ecf20Sopenharmony_ci int err; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 3468c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 3478c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 3488c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 3498c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(0)); 3508c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 3518c2ecf20Sopenharmony_ci c.u.ts.sc = FW_PTP_SC_SET_TIME; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci ns = timespec64_to_ns(ts); 3548c2ecf20Sopenharmony_ci c.u.ts.tm = cpu_to_be64(ns); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 3578c2ecf20Sopenharmony_ci if (err < 0) 3588c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 3598c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return err; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic void cxgb4_init_ptp_timer(struct adapter *adapter) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct fw_ptp_cmd c; 3678c2ecf20Sopenharmony_ci int err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci memset(&c, 0, sizeof(c)); 3708c2ecf20Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | 3718c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 3728c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 3738c2ecf20Sopenharmony_ci FW_PTP_CMD_PORTID_V(0)); 3748c2ecf20Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); 3758c2ecf20Sopenharmony_ci c.u.scmd.sc = FW_PTP_SC_INIT_TIMER; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); 3788c2ecf20Sopenharmony_ci if (err < 0) 3798c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 3808c2ecf20Sopenharmony_ci "PTP: %s error %d\n", __func__, -err); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * cxgb4_ptp_enable - enable or disable an ancillary feature 3858c2ecf20Sopenharmony_ci * @ptp: ptp clock structure 3868c2ecf20Sopenharmony_ci * @request: Desired resource to enable or disable 3878c2ecf20Sopenharmony_ci * @on: Caller passes one to enable or zero to disable 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * Enable (or disable) ancillary features of the PHC subsystem. 3908c2ecf20Sopenharmony_ci * Currently, no ancillary features are supported. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp, 3938c2ecf20Sopenharmony_ci struct ptp_clock_request __always_unused *request, 3948c2ecf20Sopenharmony_ci int __always_unused on) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci return -ENOTSUPP; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic const struct ptp_clock_info cxgb4_ptp_clock_info = { 4008c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4018c2ecf20Sopenharmony_ci .name = "cxgb4_clock", 4028c2ecf20Sopenharmony_ci .max_adj = MAX_PTP_FREQ_ADJ, 4038c2ecf20Sopenharmony_ci .n_alarm = 0, 4048c2ecf20Sopenharmony_ci .n_ext_ts = 0, 4058c2ecf20Sopenharmony_ci .n_per_out = 0, 4068c2ecf20Sopenharmony_ci .pps = 0, 4078c2ecf20Sopenharmony_ci .adjfreq = cxgb4_ptp_adjfreq, 4088c2ecf20Sopenharmony_ci .adjtime = cxgb4_ptp_adjtime, 4098c2ecf20Sopenharmony_ci .gettime64 = cxgb4_ptp_gettime, 4108c2ecf20Sopenharmony_ci .settime64 = cxgb4_ptp_settime, 4118c2ecf20Sopenharmony_ci .enable = cxgb4_ptp_enable, 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/** 4158c2ecf20Sopenharmony_ci * cxgb4_ptp_init - initialize PTP for devices which support it 4168c2ecf20Sopenharmony_ci * @adapter: board private structure 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * This function performs the required steps for enabling PTP support. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_civoid cxgb4_ptp_init(struct adapter *adapter) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct timespec64 now; 4238c2ecf20Sopenharmony_ci /* no need to create a clock device if we already have one */ 4248c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(adapter->ptp_clock)) 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 4288c2ecf20Sopenharmony_ci adapter->ptp_clock_info = cxgb4_ptp_clock_info; 4298c2ecf20Sopenharmony_ci spin_lock_init(&adapter->ptp_lock); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info, 4328c2ecf20Sopenharmony_ci &adapter->pdev->dev); 4338c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(adapter->ptp_clock)) { 4348c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 4358c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 4368c2ecf20Sopenharmony_ci "PTP %s Clock registration has failed\n", __func__); 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci now = ktime_to_timespec64(ktime_get_real()); 4418c2ecf20Sopenharmony_ci cxgb4_init_ptp_timer(adapter); 4428c2ecf20Sopenharmony_ci if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) { 4438c2ecf20Sopenharmony_ci ptp_clock_unregister(adapter->ptp_clock); 4448c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/** 4498c2ecf20Sopenharmony_ci * cxgb4_ptp_remove - disable PTP device and stop the overflow check 4508c2ecf20Sopenharmony_ci * @adapter: board private structure 4518c2ecf20Sopenharmony_ci * 4528c2ecf20Sopenharmony_ci * Stop the PTP support. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_civoid cxgb4_ptp_stop(struct adapter *adapter) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci if (adapter->ptp_tx_skb) { 4578c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 4588c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (adapter->ptp_clock) { 4628c2ecf20Sopenharmony_ci ptp_clock_unregister(adapter->ptp_clock); 4638c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci} 466