Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (C) 2021, Intel Corporation. */ #ifndef _ICE_PTP_H_ #define _ICE_PTP_H_ #include <linux/ptp_clock_kernel.h> #include <linux/kthread.h> #include "ice_ptp_hw.h" enum ice_ptp_pin_e810 { GPIO_20 = 0, GPIO_21, GPIO_22, GPIO_23, NUM_PTP_PIN_E810 }; enum ice_ptp_pin_e810t { GNSS = 0, SMA1, UFL1, SMA2, UFL2, NUM_PTP_PINS_E810T }; struct ice_perout_channel { bool ena; u32 gpio_pin; u64 period; u64 start_time; }; /* The ice hardware captures Tx hardware timestamps in the PHY. The timestamp * is stored in a buffer of registers. Depending on the specific hardware, * this buffer might be shared across multiple PHY ports. * * On transmit of a packet to be timestamped, software is responsible for * selecting an open index. Hardware makes no attempt to lock or prevent * re-use of an index for multiple packets. * * To handle this, timestamp indexes must be tracked by software to ensure * that an index is not re-used for multiple transmitted packets. The * structures and functions declared in this file track the available Tx * register indexes, as well as provide storage for the SKB pointers. * * To allow multiple ports to access the shared register block independently, * the blocks are split up so that indexes are assigned to each port based on * hardware logical port number. * * The timestamp blocks are handled differently for E810- and E822-based * devices. In E810 devices, each port has its own block of timestamps, while in * E822 there is a need to logically break the block of registers into smaller * chunks based on the port number to avoid collisions. * * Example for port 5 in E810: * +--------+--------+--------+--------+--------+--------+--------+--------+ * |register|register|register|register|register|register|register|register| * | block | block | block | block | block | block | block | block | * | for | for | for | for | for | for | for | for | * | port 0 | port 1 | port 2 | port 3 | port 4 | port 5 | port 6 | port 7 | * +--------+--------+--------+--------+--------+--------+--------+--------+ * ^^ * || * |--- quad offset is always 0 * ---- quad number * * Example for port 5 in E822: * +-----------------------------+-----------------------------+ * | register block for quad 0 | register block for quad 1 | * |+------+------+------+------+|+------+------+------+------+| * ||port 0|port 1|port 2|port 3|||port 0|port 1|port 2|port 3|| * |+------+------+------+------+|+------+------+------+------+| * +-----------------------------+-------^---------------------+ * ^ | * | --- quad offset* * ---- quad number * * * PHY port 5 is port 1 in quad 1 * */ /** * struct ice_tx_tstamp - Tracking for a single Tx timestamp * @skb: pointer to the SKB for this timestamp request * @start: jiffies when the timestamp was first requested * @cached_tstamp: last read timestamp * * This structure tracks a single timestamp request. The SKB pointer is * provided when initiating a request. The start time is used to ensure that * we discard old requests that were not fulfilled within a 2 second time * window. * Timestamp values in the PHY are read only and do not get cleared except at * hardware reset or when a new timestamp value is captured. The cached_tstamp * field is used to detect the case where a new timestamp has not yet been * captured, ensuring that we avoid sending stale timestamp data to the stack. */ struct ice_tx_tstamp { struct sk_buff *skb; unsigned long start; u64 cached_tstamp; }; /** * struct ice_ptp_tx - Tracking structure for all Tx timestamp requests on a port * @lock: lock to prevent concurrent write to in_use bitmap * @tstamps: array of len to store outstanding requests * @in_use: bitmap of len to indicate which slots are in use * @quad: which quad the timestamps are captured in * @quad_offset: offset into timestamp block of the quad to get the real index * @len: length of the tstamps and in_use fields. * @init: if true, the tracker is initialized; * @calibrating: if true, the PHY is calibrating the Tx offset. During this * window, timestamps are temporarily disabled. */ struct ice_ptp_tx { spinlock_t lock; /* lock protecting in_use bitmap */ struct ice_tx_tstamp *tstamps; unsigned long *in_use; u8 quad; u8 quad_offset; u8 len; u8 init; u8 calibrating; }; /* Quad and port information for initializing timestamp blocks */ #define INDEX_PER_QUAD 64 #define INDEX_PER_PORT (INDEX_PER_QUAD / ICE_PORTS_PER_QUAD) /** * struct ice_ptp_port - data used to initialize an external port for PTP * * This structure contains data indicating whether a single external port is * ready for PTP functionality. It is used to track the port initialization * and determine when the port's PHY offset is valid. * * @tx: Tx timestamp tracking for this port * @ov_work: delayed work task for tracking when PHY offset is valid * @ps_lock: mutex used to protect the overall PTP PHY start procedure * @link_up: indicates whether the link is up * @tx_fifo_busy_cnt: number of times the Tx FIFO was busy * @port_num: the port number this structure represents */ struct ice_ptp_port { struct ice_ptp_tx tx; struct kthread_delayed_work ov_work; struct mutex ps_lock; /* protects overall PTP PHY start procedure */ bool link_up; u8 tx_fifo_busy_cnt; u8 port_num; }; #define GLTSYN_TGT_H_IDX_MAX 4 /** * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK * @port: data for the PHY port initialization procedure * @work: delayed work function for periodic tasks * @cached_phc_time: a cached copy of the PHC time for timestamp extension * @cached_phc_jiffies: jiffies when cached_phc_time was last updated * @ext_ts_chan: the external timestamp channel in use * @ext_ts_irq: the external timestamp IRQ in use * @kworker: kwork thread for handling periodic work * @perout_channels: periodic output data * @info: structure defining PTP hardware capabilities * @clock: pointer to registered PTP clock device * @tstamp_config: hardware timestamping configuration * @reset_time: kernel time after clock stop on reset * @tx_hwtstamp_skipped: number of Tx time stamp requests skipped * @tx_hwtstamp_timeouts: number of Tx skbs discarded with no time stamp * @tx_hwtstamp_flushed: number of Tx skbs flushed due to interface closed * @tx_hwtstamp_discarded: number of Tx skbs discarded due to cached PHC time * being too old to correctly extend timestamp * @late_cached_phc_updates: number of times cached PHC update is late */ struct ice_ptp { struct ice_ptp_port port; struct kthread_delayed_work work; u64 cached_phc_time; unsigned long cached_phc_jiffies; u8 ext_ts_chan; u8 ext_ts_irq; struct kthread_worker *kworker; struct ice_perout_channel perout_channels[GLTSYN_TGT_H_IDX_MAX]; struct ptp_clock_info info; struct ptp_clock *clock; struct hwtstamp_config tstamp_config; u64 reset_time; u32 tx_hwtstamp_skipped; u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_flushed; u32 tx_hwtstamp_discarded; u32 late_cached_phc_updates; }; #define __ptp_port_to_ptp(p) \ container_of((p), struct ice_ptp, port) #define ptp_port_to_pf(p) \ container_of(__ptp_port_to_ptp((p)), struct ice_pf, ptp) #define __ptp_info_to_ptp(i) \ container_of((i), struct ice_ptp, info) #define ptp_info_to_pf(i) \ container_of(__ptp_info_to_ptp((i)), struct ice_pf, ptp) #define PFTSYN_SEM_BYTES 4 #define PTP_SHARED_CLK_IDX_VALID BIT(31) #define TS_CMD_MASK 0xF #define SYNC_EXEC_CMD 0x3 #define ICE_PTP_TS_VALID BIT(0) #define FIFO_EMPTY BIT(2) #define FIFO_OK 0xFF #define ICE_PTP_FIFO_NUM_CHECKS 5 /* Per-channel register definitions */ #define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8)) #define GLTSYN_AUX_IN(_chan, _idx) (GLTSYN_AUX_IN_0(_idx) + ((_chan) * 8)) #define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8)) #define GLTSYN_TGT_L(_chan, _idx) (GLTSYN_TGT_L_0(_idx) + ((_chan) * 16)) #define GLTSYN_TGT_H(_chan, _idx) (GLTSYN_TGT_H_0(_idx) + ((_chan) * 16)) #define GLTSYN_EVNT_L(_chan, _idx) (GLTSYN_EVNT_L_0(_idx) + ((_chan) * 16)) #define GLTSYN_EVNT_H(_chan, _idx) (GLTSYN_EVNT_H_0(_idx) + ((_chan) * 16)) #define GLTSYN_EVNT_H_IDX_MAX 3 /* Pin definitions for PTP PPS out */ #define PPS_CLK_GEN_CHAN 3 #define PPS_CLK_SRC_CHAN 2 #define PPS_PIN_INDEX 5 #define TIME_SYNC_PIN_INDEX 4 #define N_EXT_TS_E810 3 #define N_PER_OUT_E810 4 #define N_PER_OUT_E810T 3 #define N_PER_OUT_NO_SMA_E810T 2 #define N_EXT_TS_NO_SMA_E810T 2 #define ETH_GLTSYN_ENA(_i) (0x03000348 + ((_i) * 4)) #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) struct ice_pf; int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr); int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr); void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena); int ice_get_ptp_clock_index(struct ice_pf *pf); void ice_ptp_extts_event(struct ice_pf *pf); s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb); bool ice_ptp_process_ts(struct ice_pf *pf); void ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb); void ice_ptp_reset(struct ice_pf *pf); void ice_ptp_prepare_for_reset(struct ice_pf *pf); void ice_ptp_init(struct ice_pf *pf); void ice_ptp_release(struct ice_pf *pf); int ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup); #else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ static inline int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) { return -EOPNOTSUPP; } static inline int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) { return -EOPNOTSUPP; } static inline void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena) { } static inline int ice_get_ptp_clock_index(struct ice_pf *pf) { return -1; } static inline void ice_ptp_extts_event(struct ice_pf *pf) { } static inline s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb) { return -1; } static inline bool ice_ptp_process_ts(struct ice_pf *pf) { return true; } static inline void ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb) { } static inline void ice_ptp_reset(struct ice_pf *pf) { } static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf) { } static inline void ice_ptp_init(struct ice_pf *pf) { } static inline void ice_ptp_release(struct ice_pf *pf) { } static inline int ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) { return 0; } #endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ #endif /* _ICE_PTP_H_ */ |