1a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck/* Intel Ethernet Switch Host Interface Driver 2a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Copyright(c) 2013 - 2014 Intel Corporation. 3a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 4a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * This program is free software; you can redistribute it and/or modify it 5a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * under the terms and conditions of the GNU General Public License, 6a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * version 2, as published by the Free Software Foundation. 7a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 8a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * This program is distributed in the hope it will be useful, but WITHOUT 9a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * more details. 12a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 13a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * The full GNU General Public License is included in this distribution in 14a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * the file called "COPYING". 15a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 16a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Contact Information: 17a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 18a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 19a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 20a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 21a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck#include <linux/ptp_classify.h> 22a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck#include <linux/ptp_clock_kernel.h> 23a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 24a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck#include "fm10k.h" 25a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 26a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck#define FM10K_TS_TX_TIMEOUT (HZ * 15) 27a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 28a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_systime_to_hwtstamp(struct fm10k_intfc *interface, 29a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct skb_shared_hwtstamps *hwtstamp, 30a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u64 systime) 31a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 32a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 33a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 34a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck read_lock_irqsave(&interface->systime_lock, flags); 35a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck systime += interface->ptp_adjust; 36a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck read_unlock_irqrestore(&interface->systime_lock, flags); 37a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 38a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck hwtstamp->hwtstamp = ns_to_ktime(systime); 39a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 40a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 41a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic struct sk_buff *fm10k_ts_tx_skb(struct fm10k_intfc *interface, 42a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck __le16 dglort) 43a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 44a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff_head *list = &interface->ts_tx_skb_queue; 45a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff *skb; 46a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 47a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb_queue_walk(list, skb) { 48a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (FM10K_CB(skb)->fi.w.dglort == dglort) 49a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return skb; 50a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 51a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 52a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return NULL; 53a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 54a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 55a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb) 56a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 57a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff_head *list = &interface->ts_tx_skb_queue; 58a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff *clone; 59a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 60a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck __le16 dglort; 61a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 62a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* create clone for us to return on the Tx path */ 63a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck clone = skb_clone_sk(skb); 64a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!clone) 65a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return; 66a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 67a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck FM10K_CB(clone)->ts_tx_timeout = jiffies + FM10K_TS_TX_TIMEOUT; 68a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck dglort = FM10K_CB(clone)->fi.w.dglort; 69a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 70a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_lock_irqsave(&list->lock, flags); 71a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 72a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* attempt to locate any buffers with the same dglort, 73a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * if none are present then insert skb in tail of list 74a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 75a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb = fm10k_ts_tx_skb(interface, FM10K_CB(clone)->fi.w.dglort); 76a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!skb) 77a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck __skb_queue_tail(list, clone); 78a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 79a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_unlock_irqrestore(&list->lock, flags); 80a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 81a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* if list is already has one then we just free the clone */ 82a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (skb) 83a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck kfree_skb(skb); 84a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck else 85a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; 86a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 87a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 88a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ts_tx_hwtstamp(struct fm10k_intfc *interface, __le16 dglort, 89a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u64 systime) 90a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 91a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct skb_shared_hwtstamps shhwtstamps; 92a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff_head *list = &interface->ts_tx_skb_queue; 93a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff *skb; 94a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 95a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 96a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_lock_irqsave(&list->lock, flags); 97a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 98a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* attempt to locate and pull the sk_buff out of the list */ 99a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb = fm10k_ts_tx_skb(interface, dglort); 100a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (skb) 101a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck __skb_unlink(skb, list); 102a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 103a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_unlock_irqrestore(&list->lock, flags); 104a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 105a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* if not found do nothing */ 106a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!skb) 107a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return; 108a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 109a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* timestamp the sk_buff and return it to the socket */ 110a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck fm10k_systime_to_hwtstamp(interface, &shhwtstamps, systime); 111a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb_complete_tx_timestamp(skb, &shhwtstamps); 112a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 113a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 114a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ts_tx_subtask(struct fm10k_intfc *interface) 115a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 116a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff_head *list = &interface->ts_tx_skb_queue; 117a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct sk_buff *skb, *tmp; 118a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 119a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 120a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* If we're down or resetting, just bail */ 121a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (test_bit(__FM10K_DOWN, &interface->state) || 122a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck test_bit(__FM10K_RESETTING, &interface->state)) 123a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return; 124a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 125a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_lock_irqsave(&list->lock, flags); 126a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 127a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* walk though the list and flush any expired timestamp packets */ 128a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb_queue_walk_safe(list, skb, tmp) { 129a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!time_is_after_jiffies(FM10K_CB(skb)->ts_tx_timeout)) 130a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck continue; 131a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck __skb_unlink(skb, list); 132a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck kfree_skb(skb); 133a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->tx_hwtstamp_timeouts++; 134a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 135a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 136a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck spin_unlock_irqrestore(&list->lock, flags); 137a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 138a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 139a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic u64 fm10k_systime_read(struct fm10k_intfc *interface) 140a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 141a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_hw *hw = &interface->hw; 142a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 143a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return hw->mac.ops.read_systime(hw); 144a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 145a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 146a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ts_reset(struct fm10k_intfc *interface) 147a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 148a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck s64 ns = ktime_to_ns(ktime_get_real()); 149a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 150a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 151a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* reinitialize the clock */ 152a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_lock_irqsave(&interface->systime_lock, flags); 153a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ptp_adjust = fm10k_systime_read(interface) - ns; 154a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_unlock_irqrestore(&interface->systime_lock, flags); 155a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 156a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 157a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ts_init(struct fm10k_intfc *interface) 158a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 159a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* Initialize lock protecting systime access */ 160a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck rwlock_init(&interface->systime_lock); 161a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 162a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* Initialize skb queue for pending timestamp requests */ 163a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck skb_queue_head_init(&interface->ts_tx_skb_queue); 164a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 165a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* reset the clock to current kernel time */ 166a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck fm10k_ts_reset(interface); 167a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 168a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 169a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck/** 170a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * fm10k_get_ts_config - get current hardware timestamping configuration 171a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * @netdev: network interface device structure 172a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * @ifreq: ioctl data 173a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 174a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * This function returns the current timestamping settings. Rather than 175a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * attempt to deconstruct registers to fill in the values, simply keep a copy 176a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * of the old settings around, and return a copy when requested. 177a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 178a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckint fm10k_get_ts_config(struct net_device *netdev, struct ifreq *ifr) 179a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 180a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 181a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct hwtstamp_config *config = &interface->ts_config; 182a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 183a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? 184a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck -EFAULT : 0; 185a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 186a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 187a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck/** 188a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * fm10k_set_ts_config - control hardware time stamping 189a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * @netdev: network interface device structure 190a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * @ifreq: ioctl data 191a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 192a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Outgoing time stamping can be enabled and disabled. Play nice and 193a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * disable it when requested, although it shouldn't cause any overhead 194a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * when no packet needs it. At most one packet in the queue may be 195a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * marked for time stamping, otherwise it would be impossible to tell 196a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * for sure to which packet the hardware time stamp belongs. 197a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 198a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Incoming time stamping has to be configured via the hardware 199a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * filters. Not all combinations are supported, in particular event 200a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * type has to be specified. Matching the kind of event packet is 201a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * not supported, with the exception of "all V2 events regardless of 202a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * level 2 or 4". 203a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * 204a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Since hardware always timestamps Path delay packets when timestamping V2 205a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * packets, regardless of the type specified in the register, only use V2 206a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * Event mode. This more accurately tells the user what the hardware is going 207a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * to do anyways. 208a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 209a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckint fm10k_set_ts_config(struct net_device *netdev, struct ifreq *ifr) 210a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 211a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface = netdev_priv(netdev); 212a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct hwtstamp_config ts_config; 213a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 214a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (copy_from_user(&ts_config, ifr->ifr_data, sizeof(ts_config))) 215a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EFAULT; 216a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 217a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* reserved for future extensions */ 218a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (ts_config.flags) 219a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 220a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 221a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck switch (ts_config.tx_type) { 222a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_TX_OFF: 223a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck break; 224a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_TX_ON: 225a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we likely need some check here to see if this is supported */ 226a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck break; 227a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck default: 228a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -ERANGE; 229a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 230a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 231a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck switch (ts_config.rx_filter) { 232a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_NONE: 233a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->flags &= ~FM10K_FLAG_RX_TS_ENABLED; 234a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck break; 235a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 236a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 237a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 238a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 239a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 240a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 241a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 242a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 243a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 244a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_EVENT: 245a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_SYNC: 246a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 247a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck case HWTSTAMP_FILTER_ALL: 248a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->flags |= FM10K_FLAG_RX_TS_ENABLED; 249a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ts_config.rx_filter = HWTSTAMP_FILTER_ALL; 250a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck break; 251a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck default: 252a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -ERANGE; 253a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 254a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 255a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* save these settings for future reference */ 256a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ts_config = ts_config; 257a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 258a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return copy_to_user(ifr->ifr_data, &ts_config, sizeof(ts_config)) ? 259a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck -EFAULT : 0; 260a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 261a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 262a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 263a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 264a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface; 265a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_hw *hw; 266a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck int err; 267a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 268a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface = container_of(ptp, struct fm10k_intfc, ptp_caps); 269a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck hw = &interface->hw; 270a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 271a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck err = hw->mac.ops.adjust_systime(hw, ppb); 272a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 273a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* the only error we should see is if the value is out of range */ 274a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return (err == FM10K_ERR_PARAM) ? -ERANGE : err; 275a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 276a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 277a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 278a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 279a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface; 280a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 281a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 282a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface = container_of(ptp, struct fm10k_intfc, ptp_caps); 283a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 284a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_lock_irqsave(&interface->systime_lock, flags); 285a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ptp_adjust += delta; 286a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_unlock_irqrestore(&interface->systime_lock, flags); 287a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 288a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return 0; 289a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 290a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 291a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 292a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 293a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface; 294a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 295a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u64 now; 296a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 297a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface = container_of(ptp, struct fm10k_intfc, ptp_caps); 298a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 299a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck read_lock_irqsave(&interface->systime_lock, flags); 300a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck now = fm10k_systime_read(interface) + interface->ptp_adjust; 301a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck read_unlock_irqrestore(&interface->systime_lock, flags); 302a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 303a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck *ts = ns_to_timespec(now); 304a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 305a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return 0; 306a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 307a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 308a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_settime(struct ptp_clock_info *ptp, 309a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck const struct timespec *ts) 310a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 311a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface; 312a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck unsigned long flags; 313a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u64 ns = timespec_to_ns(ts); 314a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 315a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface = container_of(ptp, struct fm10k_intfc, ptp_caps); 316a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 317a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_lock_irqsave(&interface->systime_lock, flags); 318a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ptp_adjust = fm10k_systime_read(interface) - ns; 319a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck write_unlock_irqrestore(&interface->systime_lock, flags); 320a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 321a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return 0; 322a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 323a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 324a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_enable(struct ptp_clock_info *ptp, 325a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct ptp_clock_request *rq, int on) 326a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 327a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct ptp_clock_time *t = &rq->perout.period; 328a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_intfc *interface; 329a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct fm10k_hw *hw; 330a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u64 period; 331a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck u32 step; 332a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 333a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we can only support periodic output */ 334a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (rq->type != PTP_CLK_REQ_PEROUT) 335a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 336a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 337a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* verify the requested channel is there */ 338a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (rq->perout.index >= ptp->n_per_out) 339a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 340a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 341a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we cannot enforce start time as there is no 342a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * mechanism for that in the hardware, we can only control 343a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * the period. 344a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 345a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 346a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we cannot support periods greater than 4 seconds due to reg limit */ 347a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (t->sec > 4 || t->sec < 0) 348a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -ERANGE; 349a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 350a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface = container_of(ptp, struct fm10k_intfc, ptp_caps); 351a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck hw = &interface->hw; 352a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 353a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we simply cannot support the operation if we don't have BAR4 */ 354a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!hw->sw_addr) 355a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -ENOTSUPP; 356a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 357a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* convert to unsigned 64b ns, verify we can put it in a 32b register */ 358a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck period = t->sec * 1000000000LL + t->nsec; 359a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 360a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* determine the minimum size for period */ 361a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck step = 2 * (fm10k_read_reg(hw, FM10K_SYSTIME_CFG) & 362a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck FM10K_SYSTIME_CFG_STEP_MASK); 363a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 364a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* verify the value is in range supported by hardware */ 365a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if ((period && (period < step)) || (period > U32_MAX)) 366a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -ERANGE; 367a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 368a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* notify hardware of request to being sending pulses */ 369a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck fm10k_write_sw_reg(hw, FM10K_SW_SYSTIME_PULSE(rq->perout.index), 370a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck (u32)period); 371a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 372a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return 0; 373a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 374a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 375a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic struct ptp_pin_desc fm10k_ptp_pd[2] = { 376a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck { 377a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .name = "IEEE1588_PULSE0", 378a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .index = 0, 379a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .func = PTP_PF_PEROUT, 380a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .chan = 0 381a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck }, 382a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck { 383a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .name = "IEEE1588_PULSE1", 384a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .index = 1, 385a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .func = PTP_PF_PEROUT, 386a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck .chan = 1 387a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 388a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck}; 389a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 390a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckstatic int fm10k_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, 391a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck enum ptp_pin_function func, unsigned int chan) 392a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 393a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* verify the requested pin is there */ 394a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (pin >= ptp->n_pins || !ptp->pin_config) 395a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 396a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 397a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* enforce locked channels, no changing them */ 398a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (chan != ptp->pin_config[pin].chan) 399a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 400a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 401a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* we want to keep the functions locked as well */ 402a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (func != ptp->pin_config[pin].func) 403a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return -EINVAL; 404a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 405a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return 0; 406a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 407a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 408a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ptp_register(struct fm10k_intfc *interface) 409a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 410a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct ptp_clock_info *ptp_caps = &interface->ptp_caps; 411a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct device *dev = &interface->pdev->dev; 412a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct ptp_clock *ptp_clock; 413a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 414a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck snprintf(ptp_caps->name, sizeof(ptp_caps->name), 415a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck "%s", interface->netdev->name); 416a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->owner = THIS_MODULE; 417a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* This math is simply the inverse of the math in 418a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * fm10k_adjust_systime_pf applied to an adjustment value 419a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * of 2^30 - 1 which is the maximum value of the register: 420a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck * max_ppb == ((2^30 - 1) * 5^9) / 2^31 421a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck */ 422a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->max_adj = 976562; 423a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->adjfreq = fm10k_ptp_adjfreq; 424a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->adjtime = fm10k_ptp_adjtime; 425a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->gettime = fm10k_ptp_gettime; 426a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->settime = fm10k_ptp_settime; 427a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 428a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* provide pins if BAR4 is accessible */ 429a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (interface->sw_addr) { 430a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* enable periodic outputs */ 431a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->n_per_out = 2; 432a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->enable = fm10k_ptp_enable; 433a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 434a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck /* enable clock pins */ 435a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->verify = fm10k_ptp_verify; 436a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->n_pins = 2; 437a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_caps->pin_config = fm10k_ptp_pd; 438a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 439a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 440a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_clock = ptp_clock_register(ptp_caps, dev); 441a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (IS_ERR(ptp_clock)) { 442a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_clock = NULL; 443a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck dev_err(dev, "ptp_clock_register failed\n"); 444a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } else { 445a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck dev_info(dev, "registered PHC device %s\n", ptp_caps->name); 446a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck } 447a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 448a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ptp_clock = ptp_clock; 449a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 450a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 451a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyckvoid fm10k_ptp_unregister(struct fm10k_intfc *interface) 452a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck{ 453a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct ptp_clock *ptp_clock = interface->ptp_clock; 454a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck struct device *dev = &interface->pdev->dev; 455a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 456a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck if (!ptp_clock) 457a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck return; 458a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 459a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck interface->ptp_clock = NULL; 460a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck 461a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck ptp_clock_unregister(ptp_clock); 462a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck dev_info(dev, "removed PHC %s\n", interface->ptp_caps.name); 463a211e0136c9a3653acba13ec3b9a2f49c3c44f5eAlexander Duyck} 464