]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
net/mlx5: Fix E-Switch flow steering capabilities check
[mirror_ubuntu-artful-kernel.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_clock.c
1 /*
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
36 enum {
37 MLX5E_CYCLES_SHIFT = 23
38 };
39
40 void 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
52 static 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
60 static 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);
65 unsigned long flags;
66
67 write_lock_irqsave(&tstamp->lock, flags);
68 timecounter_read(&tstamp->clock);
69 write_unlock_irqrestore(&tstamp->lock, flags);
70 schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
71 }
72
73 int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr)
74 {
75 struct mlx5e_priv *priv = netdev_priv(dev);
76 struct hwtstamp_config config;
77
78 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
79 return -EOPNOTSUPP;
80
81 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
82 return -EFAULT;
83
84 /* TX HW timestamp */
85 switch (config.tx_type) {
86 case HWTSTAMP_TX_OFF:
87 case HWTSTAMP_TX_ON:
88 break;
89 default:
90 return -ERANGE;
91 }
92
93 /* RX HW timestamp */
94 switch (config.rx_filter) {
95 case HWTSTAMP_FILTER_NONE:
96 /* Reset CQE compression to Admin default */
97 mlx5e_modify_rx_cqe_compression(priv, priv->params.rx_cqe_compress_admin);
98 break;
99 case HWTSTAMP_FILTER_ALL:
100 case HWTSTAMP_FILTER_SOME:
101 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
102 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
103 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
104 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
105 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
106 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
107 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
108 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
109 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
110 case HWTSTAMP_FILTER_PTP_V2_EVENT:
111 case HWTSTAMP_FILTER_PTP_V2_SYNC:
112 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
113 /* Disable CQE compression */
114 mlx5e_modify_rx_cqe_compression(priv, false);
115 config.rx_filter = HWTSTAMP_FILTER_ALL;
116 break;
117 default:
118 return -ERANGE;
119 }
120
121 memcpy(&priv->tstamp.hwtstamp_config, &config, sizeof(config));
122
123 return copy_to_user(ifr->ifr_data, &config,
124 sizeof(config)) ? -EFAULT : 0;
125 }
126
127 int mlx5e_hwstamp_get(struct net_device *dev, struct ifreq *ifr)
128 {
129 struct mlx5e_priv *priv = netdev_priv(dev);
130 struct hwtstamp_config *cfg = &priv->tstamp.hwtstamp_config;
131
132 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
133 return -EOPNOTSUPP;
134
135 return copy_to_user(ifr->ifr_data, cfg, sizeof(*cfg)) ? -EFAULT : 0;
136 }
137
138 static int mlx5e_ptp_settime(struct ptp_clock_info *ptp,
139 const struct timespec64 *ts)
140 {
141 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
142 ptp_info);
143 u64 ns = timespec64_to_ns(ts);
144 unsigned long flags;
145
146 write_lock_irqsave(&tstamp->lock, flags);
147 timecounter_init(&tstamp->clock, &tstamp->cycles, ns);
148 write_unlock_irqrestore(&tstamp->lock, flags);
149
150 return 0;
151 }
152
153 static int mlx5e_ptp_gettime(struct ptp_clock_info *ptp,
154 struct timespec64 *ts)
155 {
156 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
157 ptp_info);
158 u64 ns;
159 unsigned long flags;
160
161 write_lock_irqsave(&tstamp->lock, flags);
162 ns = timecounter_read(&tstamp->clock);
163 write_unlock_irqrestore(&tstamp->lock, flags);
164
165 *ts = ns_to_timespec64(ns);
166
167 return 0;
168 }
169
170 static int mlx5e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
171 {
172 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
173 ptp_info);
174 unsigned long flags;
175
176 write_lock_irqsave(&tstamp->lock, flags);
177 timecounter_adjtime(&tstamp->clock, delta);
178 write_unlock_irqrestore(&tstamp->lock, flags);
179
180 return 0;
181 }
182
183 static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
184 {
185 u64 adj;
186 u32 diff;
187 unsigned long flags;
188 int neg_adj = 0;
189 struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
190 ptp_info);
191
192 if (delta < 0) {
193 neg_adj = 1;
194 delta = -delta;
195 }
196
197 adj = tstamp->nominal_c_mult;
198 adj *= delta;
199 diff = div_u64(adj, 1000000000ULL);
200
201 write_lock_irqsave(&tstamp->lock, flags);
202 timecounter_read(&tstamp->clock);
203 tstamp->cycles.mult = neg_adj ? tstamp->nominal_c_mult - diff :
204 tstamp->nominal_c_mult + diff;
205 write_unlock_irqrestore(&tstamp->lock, flags);
206
207 return 0;
208 }
209
210 static const struct ptp_clock_info mlx5e_ptp_clock_info = {
211 .owner = THIS_MODULE,
212 .max_adj = 100000000,
213 .n_alarm = 0,
214 .n_ext_ts = 0,
215 .n_per_out = 0,
216 .n_pins = 0,
217 .pps = 0,
218 .adjfreq = mlx5e_ptp_adjfreq,
219 .adjtime = mlx5e_ptp_adjtime,
220 .gettime64 = mlx5e_ptp_gettime,
221 .settime64 = mlx5e_ptp_settime,
222 .enable = NULL,
223 };
224
225 static void mlx5e_timestamp_init_config(struct mlx5e_tstamp *tstamp)
226 {
227 tstamp->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
228 tstamp->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
229 }
230
231 void mlx5e_timestamp_init(struct mlx5e_priv *priv)
232 {
233 struct mlx5e_tstamp *tstamp = &priv->tstamp;
234 u64 ns;
235 u64 frac = 0;
236 u32 dev_freq;
237
238 mlx5e_timestamp_init_config(tstamp);
239 dev_freq = MLX5_CAP_GEN(priv->mdev, device_frequency_khz);
240 if (!dev_freq) {
241 mlx5_core_warn(priv->mdev, "invalid device_frequency_khz, aborting HW clock init\n");
242 return;
243 }
244 rwlock_init(&tstamp->lock);
245 tstamp->cycles.read = mlx5e_read_internal_timer;
246 tstamp->cycles.shift = MLX5E_CYCLES_SHIFT;
247 tstamp->cycles.mult = clocksource_khz2mult(dev_freq,
248 tstamp->cycles.shift);
249 tstamp->nominal_c_mult = tstamp->cycles.mult;
250 tstamp->cycles.mask = CLOCKSOURCE_MASK(41);
251 tstamp->mdev = priv->mdev;
252
253 timecounter_init(&tstamp->clock, &tstamp->cycles,
254 ktime_to_ns(ktime_get_real()));
255
256 /* Calculate period in seconds to call the overflow watchdog - to make
257 * sure counter is checked at least once every wrap around.
258 */
259 ns = cyclecounter_cyc2ns(&tstamp->cycles, tstamp->cycles.mask,
260 frac, &frac);
261 do_div(ns, NSEC_PER_SEC / 2 / HZ);
262 tstamp->overflow_period = ns;
263
264 INIT_DELAYED_WORK(&tstamp->overflow_work, mlx5e_timestamp_overflow);
265 if (tstamp->overflow_period)
266 schedule_delayed_work(&tstamp->overflow_work, 0);
267 else
268 mlx5_core_warn(priv->mdev, "invalid overflow period, overflow_work is not scheduled\n");
269
270 /* Configure the PHC */
271 tstamp->ptp_info = mlx5e_ptp_clock_info;
272 snprintf(tstamp->ptp_info.name, 16, "mlx5 ptp");
273
274 tstamp->ptp = ptp_clock_register(&tstamp->ptp_info,
275 &priv->mdev->pdev->dev);
276 if (IS_ERR_OR_NULL(tstamp->ptp)) {
277 mlx5_core_warn(priv->mdev, "ptp_clock_register failed %ld\n",
278 PTR_ERR(tstamp->ptp));
279 tstamp->ptp = NULL;
280 }
281 }
282
283 void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv)
284 {
285 struct mlx5e_tstamp *tstamp = &priv->tstamp;
286
287 if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz))
288 return;
289
290 if (priv->tstamp.ptp) {
291 ptp_clock_unregister(priv->tstamp.ptp);
292 priv->tstamp.ptp = NULL;
293 }
294
295 cancel_delayed_work_sync(&tstamp->overflow_work);
296 }