blob: fddcff0155228fbaaa8af6f10c5080bc6b5955de [file] [log] [blame]
Eran Ben Elishaef9814d2015-12-29 14:58:31 +02001/*
2 * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33#include <linux/clocksource.h>
34#include "en.h"
35
36enum {
37 MLX5E_CYCLES_SHIFT = 23
38};
39
40void mlx5e_fill_hwstamp(struct mlx5e_tstamp *tstamp, u64 timestamp,
41 struct skb_shared_hwtstamps *hwts)
42{
43 u64 nsec;
44
45 read_lock(&tstamp->lock);
46 nsec = timecounter_cyc2time(&tstamp->clock, timestamp);
47 read_unlock(&tstamp->lock);
48
49 hwts->hwtstamp = ns_to_ktime(nsec);
50}
51
52static cycle_t mlx5e_read_internal_timer(const struct cyclecounter *cc)
53{
54 struct mlx5e_tstamp *tstamp = container_of(cc, struct mlx5e_tstamp,
55 cycles);
56
57 return mlx5_read_internal_timer(tstamp->mdev) & cc->mask;
58}
59
60static void mlx5e_timestamp_overflow(struct work_struct *work)
61{
62 struct delayed_work *dwork = to_delayed_work(work);
63 struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
64 overflow_work);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +020065 unsigned long flags;
Eran Ben Elishaef9814d2015-12-29 14:58:31 +020066
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +020067 write_lock_irqsave(&tstamp->lock, flags);
Eran Ben Elishaef9814d2015-12-29 14:58:31 +020068 timecounter_read(&tstamp->clock);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +020069 write_unlock_irqrestore(&tstamp->lock, flags);
Eugenia Emantayev862ade92017-07-12 17:27:18 +030070 schedule_delayed_work(&tstamp->overflow_work,
71 msecs_to_jiffies(tstamp->overflow_period * 1000));
Eran Ben Elishaef9814d2015-12-29 14:58:31 +020072}
73
74int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
75{
76 struct mlx5e_priv *priv = netdev_priv(dev);
77 struct hwtstamp_config config;
78
79 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
80 return -EOPNOTSUPP;
81
82 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
83 return -EFAULT;
84
85 /* TX HW timestamp */
86 switch (config.tx_type) {
87 case HWTSTAMP_TX_OFF:
88 case HWTSTAMP_TX_ON:
89 break;
90 default:
91 return -ERANGE;
92 }
93
94 /* RX HW timestamp */
95 switch (config.rx_filter) {
96 case HWTSTAMP_FILTER_NONE:
Tariq Toukan7219ab32016-05-11 00:29:14 +030097 /* Reset CQE compression to Admin default */
98 mlx5e_modify_rx_cqe_compression(priv, priv->params.rx_cqe_compress_admin);
Eran Ben Elishaef9814d2015-12-29 14:58:31 +020099 break;
100 case HWTSTAMP_FILTER_ALL:
101 case HWTSTAMP_FILTER_SOME:
102 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
103 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
104 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
105 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
106 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
107 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
108 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
109 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
110 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
111 case HWTSTAMP_FILTER_PTP_V2_EVENT:
112 case HWTSTAMP_FILTER_PTP_V2_SYNC:
113 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
Tariq Toukan7219ab32016-05-11 00:29:14 +0300114 /* Disable CQE compression */
115 mlx5e_modify_rx_cqe_compression(priv, false);
Eran Ben Elishaef9814d2015-12-29 14:58:31 +0200116 config.rx_filter = HWTSTAMP_FILTER_ALL;
117 break;
118 default:
119 return -ERANGE;
120 }
121
122 memcpy(&priv->tstamp.hwtstamp_config, &config, sizeof(config));
123
124 return copy_to_user(ifr->ifr_data, &config,
125 sizeof(config)) ? -EFAULT : 0;
126}
127
128int mlx5e_hwstamp_get(struct net_device *dev, struct ifreq *ifr)
129{
130 struct mlx5e_priv *priv = netdev_priv(dev);
131 struct hwtstamp_config *cfg = &priv->tstamp.hwtstamp_config;
132
133 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
134 return -EOPNOTSUPP;
135
136 return copy_to_user(ifr->ifr_data, cfg, sizeof(*cfg)) ? -EFAULT : 0;
137}
138
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200139static int mlx5e_ptp_settime(struct ptp_clock_info *ptp,
140 const struct timespec64 *ts)
141{
142 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
143 ptp_info);
144 u64 ns = timespec64_to_ns(ts);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200145 unsigned long flags;
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200146
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200147 write_lock_irqsave(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200148 timecounter_init(&tstamp->clock, &tstamp->cycles, ns);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200149 write_unlock_irqrestore(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200150
151 return 0;
152}
153
154static int mlx5e_ptp_gettime(struct ptp_clock_info *ptp,
155 struct timespec64 *ts)
156{
157 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
158 ptp_info);
159 u64 ns;
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200160 unsigned long flags;
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200161
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200162 write_lock_irqsave(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200163 ns = timecounter_read(&tstamp->clock);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200164 write_unlock_irqrestore(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200165
166 *ts = ns_to_timespec64(ns);
167
168 return 0;
169}
170
171static int mlx5e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
172{
173 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
174 ptp_info);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200175 unsigned long flags;
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200176
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200177 write_lock_irqsave(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200178 timecounter_adjtime(&tstamp->clock, delta);
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200179 write_unlock_irqrestore(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200180
181 return 0;
182}
183
184static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
185{
186 u64 adj;
187 u32 diff;
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200188 unsigned long flags;
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200189 int neg_adj = 0;
190 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
191 ptp_info);
192
193 if (delta < 0) {
194 neg_adj = 1;
195 delta = -delta;
196 }
197
198 adj = tstamp->nominal_c_mult;
199 adj *= delta;
200 diff = div_u64(adj, 1000000000ULL);
201
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200202 write_lock_irqsave(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200203 timecounter_read(&tstamp->clock);
204 tstamp->cycles.mult = neg_adj ? tstamp->nominal_c_mult - diff :
205 tstamp->nominal_c_mult + diff;
Eran Ben Elisha0ad9b202016-02-29 21:17:11 +0200206 write_unlock_irqrestore(&tstamp->lock, flags);
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200207
208 return 0;
209}
210
211static const struct ptp_clock_info mlx5e_ptp_clock_info = {
212 .owner = THIS_MODULE,
213 .max_adj = 100000000,
214 .n_alarm = 0,
215 .n_ext_ts = 0,
216 .n_per_out = 0,
217 .n_pins = 0,
218 .pps = 0,
219 .adjfreq = mlx5e_ptp_adjfreq,
220 .adjtime = mlx5e_ptp_adjtime,
221 .gettime64 = mlx5e_ptp_gettime,
222 .settime64 = mlx5e_ptp_settime,
223 .enable = NULL,
224};
225
Eran Ben Elishaef9814d2015-12-29 14:58:31 +0200226static void mlx5e_timestamp_init_config(struct mlx5e_tstamp *tstamp)
227{
228 tstamp->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
229 tstamp->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
230}
231
232void mlx5e_timestamp_init(struct mlx5e_priv *priv)
233{
234 struct mlx5e_tstamp *tstamp = &priv->tstamp;
235 u64 ns;
236 u64 frac = 0;
237 u32 dev_freq;
238
239 mlx5e_timestamp_init_config(tstamp);
240 dev_freq = MLX5_CAP_GEN(priv->mdev, device_frequency_khz);
241 if (!dev_freq) {
242 mlx5_core_warn(priv->mdev, "invalid device_frequency_khz, aborting HW clock init\n");
243 return;
244 }
245 rwlock_init(&tstamp->lock);
246 tstamp->cycles.read = mlx5e_read_internal_timer;
247 tstamp->cycles.shift = MLX5E_CYCLES_SHIFT;
248 tstamp->cycles.mult = clocksource_khz2mult(dev_freq,
249 tstamp->cycles.shift);
250 tstamp->nominal_c_mult = tstamp->cycles.mult;
251 tstamp->cycles.mask = CLOCKSOURCE_MASK(41);
252 tstamp->mdev = priv->mdev;
253
254 timecounter_init(&tstamp->clock, &tstamp->cycles,
255 ktime_to_ns(ktime_get_real()));
256
257 /* Calculate period in seconds to call the overflow watchdog - to make
258 * sure counter is checked at least once every wrap around.
259 */
260 ns = cyclecounter_cyc2ns(&tstamp->cycles, tstamp->cycles.mask,
261 frac, &frac);
262 do_div(ns, NSEC_PER_SEC / 2 / HZ);
263 tstamp->overflow_period = ns;
264
265 INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
266 if (tstamp->overflow_period)
267 schedule_delayed_work(&tstamp->overflow_work, 0);
268 else
269 mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200270
271 /* Configure the PHC */
272 tstamp->ptp_info = mlx5e_ptp_clock_info;
273 snprintf(tstamp->ptp_info.name, 16, "mlx5 ptp");
274
275 tstamp->ptp = ptp_clock_register(&tstamp->ptp_info,
276 &priv->mdev->pdev->dev);
Nicolas Pitreefee95f2016-09-20 19:25:58 -0400277 if (IS_ERR(tstamp->ptp)) {
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200278 mlx5_core_warn(priv->mdev, "ptp_clock_register failed %ld\n",
279 PTR_ERR(tstamp->ptp));
280 tstamp->ptp = NULL;
281 }
Eran Ben Elishaef9814d2015-12-29 14:58:31 +0200282}
283
284void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv)
285{
286 struct mlx5e_tstamp *tstamp = &priv->tstamp;
287
288 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
289 return;
290
Eran Ben Elisha3d8c38a2015-12-29 14:58:32 +0200291 if (priv->tstamp.ptp) {
292 ptp_clock_unregister(priv->tstamp.ptp);
293 priv->tstamp.ptp = NULL;
294 }
295
Eran Ben Elishaef9814d2015-12-29 14:58:31 +0200296 cancel_delayed_work_sync(&tstamp->overflow_work);
297}