xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/dpll.c (revision 9c11fcb2e9a54d0f1467380831e2e4bb68f7498d)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3 
4 #include <linux/dpll.h>
5 #include <linux/mlx5/driver.h>
6 
7 /* This structure represents a reference to DPLL, one is created
8  * per mdev instance.
9  */
10 struct mlx5_dpll {
11 	struct dpll_device *dpll;
12 	dpll_tracker dpll_tracker;
13 	struct dpll_pin *dpll_pin;
14 	dpll_tracker pin_tracker;
15 	struct mlx5_core_dev *mdev;
16 	struct workqueue_struct *wq;
17 	struct delayed_work work;
18 	struct {
19 		bool valid;
20 		enum dpll_lock_status lock_status;
21 		enum dpll_pin_state pin_state;
22 	} last;
23 	struct notifier_block mdev_nb;
24 	struct net_device *tracking_netdev;
25 };
26 
27 static int mlx5_dpll_clock_id_get(struct mlx5_core_dev *mdev, u64 *clock_id)
28 {
29 	u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {};
30 	u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {};
31 	int err;
32 
33 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
34 				   MLX5_REG_MSECQ, 0, 0);
35 	if (err)
36 		return err;
37 	*clock_id = MLX5_GET64(msecq_reg, out, local_clock_identity);
38 	return 0;
39 }
40 
41 struct mlx5_dpll_synce_status {
42 	enum mlx5_msees_admin_status admin_status;
43 	enum mlx5_msees_oper_status oper_status;
44 	bool ho_acq;
45 	bool oper_freq_measure;
46 	enum mlx5_msees_failure_reason failure_reason;
47 	s32 frequency_diff;
48 };
49 
50 static int
51 mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
52 			   struct mlx5_dpll_synce_status *synce_status)
53 {
54 	u32 out[MLX5_ST_SZ_DW(msees_reg)] = {};
55 	u32 in[MLX5_ST_SZ_DW(msees_reg)] = {};
56 	int err;
57 
58 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
59 				   MLX5_REG_MSEES, 0, 0);
60 	if (err)
61 		return err;
62 	synce_status->admin_status = MLX5_GET(msees_reg, out, admin_status);
63 	synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status);
64 	synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq);
65 	synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure);
66 	synce_status->failure_reason = MLX5_GET(msees_reg, out, failure_reason);
67 	synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff);
68 	return 0;
69 }
70 
71 static int
72 mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev,
73 			   enum mlx5_msees_admin_status admin_status)
74 {
75 	u32 out[MLX5_ST_SZ_DW(msees_reg)] = {};
76 	u32 in[MLX5_ST_SZ_DW(msees_reg)] = {};
77 
78 	MLX5_SET(msees_reg, in, field_select,
79 		 MLX5_MSEES_FIELD_SELECT_ENABLE |
80 		 MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE |
81 		 MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS);
82 	MLX5_SET(msees_reg, in, admin_status, admin_status);
83 	MLX5_SET(msees_reg, in, admin_freq_measure, true);
84 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
85 				    MLX5_REG_MSEES, 0, 1);
86 }
87 
88 static enum dpll_lock_status
89 mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status)
90 {
91 	switch (synce_status->oper_status) {
92 	case MLX5_MSEES_OPER_STATUS_SELF_TRACK:
93 		fallthrough;
94 	case MLX5_MSEES_OPER_STATUS_OTHER_TRACK:
95 		return synce_status->ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
96 					      DPLL_LOCK_STATUS_LOCKED;
97 	case MLX5_MSEES_OPER_STATUS_HOLDOVER:
98 		fallthrough;
99 	case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER:
100 		return DPLL_LOCK_STATUS_HOLDOVER;
101 	default:
102 		return DPLL_LOCK_STATUS_UNLOCKED;
103 	}
104 }
105 
106 static enum dpll_lock_status_error
107 mlx5_dpll_lock_status_error_get(struct mlx5_dpll_synce_status *synce_status)
108 {
109 	switch (synce_status->oper_status) {
110 	case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER:
111 		fallthrough;
112 	case MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING:
113 		switch (synce_status->failure_reason) {
114 		case MLX5_MSEES_FAILURE_REASON_PORT_DOWN:
115 			return DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN;
116 		case MLX5_MSEES_FAILURE_REASON_TOO_HIGH_FREQUENCY_DIFF:
117 			return DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH;
118 		default:
119 			return DPLL_LOCK_STATUS_ERROR_UNDEFINED;
120 		}
121 	default:
122 		return DPLL_LOCK_STATUS_ERROR_NONE;
123 	}
124 }
125 
126 static enum dpll_pin_state
127 mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status)
128 {
129 	return (synce_status->admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
130 		(synce_status->oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
131 		 synce_status->oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
132 	       DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED;
133 }
134 
135 static int
136 mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status,
137 		      s64 *ffo)
138 {
139 	if (!synce_status->oper_freq_measure)
140 		return -ENODATA;
141 	*ffo = 1000000LL * synce_status->frequency_diff;
142 	return 0;
143 }
144 
145 static int
146 mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, void *priv,
147 				 enum dpll_lock_status *status,
148 				 enum dpll_lock_status_error *status_error,
149 				 struct netlink_ext_ack *extack)
150 {
151 	struct mlx5_dpll_synce_status synce_status;
152 	struct mlx5_dpll *mdpll = priv;
153 	int err;
154 
155 	err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
156 	if (err)
157 		return err;
158 	*status = mlx5_dpll_lock_status_get(&synce_status);
159 	*status_error = mlx5_dpll_lock_status_error_get(&synce_status);
160 	return 0;
161 }
162 
163 static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll,
164 				     void *priv, enum dpll_mode *mode,
165 				     struct netlink_ext_ack *extack)
166 {
167 	*mode = DPLL_MODE_MANUAL;
168 	return 0;
169 }
170 
171 enum {
172 	MLX5_DPLL_SSM_CODE_PRC = 0b0010,
173 	MLX5_DPLL_SSM_CODE_SSU_A = 0b0100,
174 	MLX5_DPLL_SSM_CODE_SSU_B = 0b1000,
175 	MLX5_DPLL_SSM_CODE_EEC1 = 0b1011,
176 	MLX5_DPLL_SSM_CODE_PRTC = 0b0010,
177 	MLX5_DPLL_SSM_CODE_EPRTC = 0b0010,
178 	MLX5_DPLL_SSM_CODE_EEEC = 0b1011,
179 	MLX5_DPLL_SSM_CODE_EPRC = 0b0010,
180 };
181 
182 enum {
183 	MLX5_DPLL_ENHANCED_SSM_CODE_PRC = 0xff,
184 	MLX5_DPLL_ENHANCED_SSM_CODE_SSU_A = 0xff,
185 	MLX5_DPLL_ENHANCED_SSM_CODE_SSU_B = 0xff,
186 	MLX5_DPLL_ENHANCED_SSM_CODE_EEC1 = 0xff,
187 	MLX5_DPLL_ENHANCED_SSM_CODE_PRTC = 0x20,
188 	MLX5_DPLL_ENHANCED_SSM_CODE_EPRTC = 0x21,
189 	MLX5_DPLL_ENHANCED_SSM_CODE_EEEC = 0x22,
190 	MLX5_DPLL_ENHANCED_SSM_CODE_EPRC = 0x23,
191 };
192 
193 #define __MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code)		\
194 	((ssm_code) | ((enhanced_ssm_code) << 8))
195 
196 #define MLX5_DPLL_SSM_COMBINED_CODE(type)					\
197 	__MLX5_DPLL_SSM_COMBINED_CODE(MLX5_DPLL_SSM_CODE_##type,		\
198 				      MLX5_DPLL_ENHANCED_SSM_CODE_##type)
199 
200 static int mlx5_dpll_clock_quality_level_get(const struct dpll_device *dpll,
201 					     void *priv, unsigned long *qls,
202 					     struct netlink_ext_ack *extack)
203 {
204 	u8 network_option, ssm_code, enhanced_ssm_code;
205 	u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {};
206 	u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {};
207 	struct mlx5_dpll *mdpll = priv;
208 	int err;
209 
210 	err = mlx5_core_access_reg(mdpll->mdev, in, sizeof(in),
211 				   out, sizeof(out), MLX5_REG_MSECQ, 0, 0);
212 	if (err)
213 		return err;
214 	network_option = MLX5_GET(msecq_reg, out, network_option);
215 	if (network_option != 1)
216 		goto errout;
217 	ssm_code = MLX5_GET(msecq_reg, out, local_ssm_code);
218 	enhanced_ssm_code = MLX5_GET(msecq_reg, out, local_enhanced_ssm_code);
219 
220 	switch (__MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code)) {
221 	case MLX5_DPLL_SSM_COMBINED_CODE(PRC):
222 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC, qls);
223 		return 0;
224 	case MLX5_DPLL_SSM_COMBINED_CODE(SSU_A):
225 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A, qls);
226 		return 0;
227 	case MLX5_DPLL_SSM_COMBINED_CODE(SSU_B):
228 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B, qls);
229 		return 0;
230 	case MLX5_DPLL_SSM_COMBINED_CODE(EEC1):
231 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1, qls);
232 		return 0;
233 	case MLX5_DPLL_SSM_COMBINED_CODE(PRTC):
234 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC, qls);
235 		return 0;
236 	case MLX5_DPLL_SSM_COMBINED_CODE(EPRTC):
237 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC, qls);
238 		return 0;
239 	case MLX5_DPLL_SSM_COMBINED_CODE(EEEC):
240 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC, qls);
241 		return 0;
242 	case MLX5_DPLL_SSM_COMBINED_CODE(EPRC):
243 		__set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC, qls);
244 		return 0;
245 	}
246 errout:
247 	NL_SET_ERR_MSG_MOD(extack, "Invalid clock quality level obtained from firmware");
248 	return -EINVAL;
249 }
250 
251 static const struct dpll_device_ops mlx5_dpll_device_ops = {
252 	.lock_status_get = mlx5_dpll_device_lock_status_get,
253 	.mode_get = mlx5_dpll_device_mode_get,
254 	.clock_quality_level_get = mlx5_dpll_clock_quality_level_get,
255 };
256 
257 static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin,
258 				       void *pin_priv,
259 				       const struct dpll_device *dpll,
260 				       void *dpll_priv,
261 				       enum dpll_pin_direction *direction,
262 				       struct netlink_ext_ack *extack)
263 {
264 	*direction = DPLL_PIN_DIRECTION_INPUT;
265 	return 0;
266 }
267 
268 static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin,
269 				       void *pin_priv,
270 				       const struct dpll_device *dpll,
271 				       void *dpll_priv,
272 				       enum dpll_pin_state *state,
273 				       struct netlink_ext_ack *extack)
274 {
275 	struct mlx5_dpll_synce_status synce_status;
276 	struct mlx5_dpll *mdpll = pin_priv;
277 	int err;
278 
279 	err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
280 	if (err)
281 		return err;
282 	*state = mlx5_dpll_pin_state_get(&synce_status);
283 	return 0;
284 }
285 
286 static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
287 				       void *pin_priv,
288 				       const struct dpll_device *dpll,
289 				       void *dpll_priv,
290 				       enum dpll_pin_state state,
291 				       struct netlink_ext_ack *extack)
292 {
293 	struct mlx5_dpll *mdpll = pin_priv;
294 
295 	return mlx5_dpll_synce_status_set(mdpll->mdev,
296 					  state == DPLL_PIN_STATE_CONNECTED ?
297 					  MLX5_MSEES_ADMIN_STATUS_TRACK :
298 					  MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING);
299 }
300 
301 static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
302 			     const struct dpll_device *dpll, void *dpll_priv,
303 			     struct dpll_ffo_param *ffo,
304 			     struct netlink_ext_ack *extack)
305 {
306 	struct mlx5_dpll_synce_status synce_status;
307 	struct mlx5_dpll *mdpll = pin_priv;
308 	int err;
309 
310 	err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
311 	if (err)
312 		return err;
313 	return mlx5_dpll_pin_ffo_get(&synce_status, &ffo->ffo);
314 }
315 
316 static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
317 	.supported_ffo = BIT(DPLL_FFO_PORT_RXTX_RATE),
318 	.direction_get = mlx5_dpll_pin_direction_get,
319 	.state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
320 	.state_on_dpll_set = mlx5_dpll_state_on_dpll_set,
321 	.ffo_get = mlx5_dpll_ffo_get,
322 };
323 
324 static const struct dpll_pin_properties mlx5_dpll_pin_properties = {
325 	.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT,
326 	.capabilities = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE,
327 };
328 
329 #define MLX5_DPLL_PERIODIC_WORK_INTERVAL 500 /* ms */
330 
331 static void mlx5_dpll_periodic_work_queue(struct mlx5_dpll *mdpll)
332 {
333 	queue_delayed_work(mdpll->wq, &mdpll->work,
334 			   msecs_to_jiffies(MLX5_DPLL_PERIODIC_WORK_INTERVAL));
335 }
336 
337 static void mlx5_dpll_periodic_work(struct work_struct *work)
338 {
339 	struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll,
340 					       work.work);
341 	struct mlx5_dpll_synce_status synce_status;
342 	enum dpll_lock_status lock_status;
343 	enum dpll_pin_state pin_state;
344 	int err;
345 
346 	err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
347 	if (err)
348 		goto err_out;
349 	lock_status = mlx5_dpll_lock_status_get(&synce_status);
350 	pin_state = mlx5_dpll_pin_state_get(&synce_status);
351 
352 	if (!mdpll->last.valid)
353 		goto invalid_out;
354 
355 	if (mdpll->last.lock_status != lock_status)
356 		dpll_device_change_ntf(mdpll->dpll);
357 	if (mdpll->last.pin_state != pin_state)
358 		dpll_pin_change_ntf(mdpll->dpll_pin);
359 
360 invalid_out:
361 	mdpll->last.lock_status = lock_status;
362 	mdpll->last.pin_state = pin_state;
363 	mdpll->last.valid = true;
364 err_out:
365 	mlx5_dpll_periodic_work_queue(mdpll);
366 }
367 
368 static void mlx5_dpll_netdev_dpll_pin_set(struct mlx5_dpll *mdpll,
369 					  struct net_device *netdev)
370 {
371 	if (mdpll->tracking_netdev)
372 		return;
373 	dpll_netdev_pin_set(netdev, mdpll->dpll_pin);
374 	mdpll->tracking_netdev = netdev;
375 }
376 
377 static void mlx5_dpll_netdev_dpll_pin_clear(struct mlx5_dpll *mdpll)
378 {
379 	if (!mdpll->tracking_netdev)
380 		return;
381 	dpll_netdev_pin_clear(mdpll->tracking_netdev);
382 	mdpll->tracking_netdev = NULL;
383 }
384 
385 static int mlx5_dpll_mdev_notifier_event(struct notifier_block *nb,
386 					 unsigned long event, void *data)
387 {
388 	struct mlx5_dpll *mdpll = container_of(nb, struct mlx5_dpll, mdev_nb);
389 	struct net_device *netdev = data;
390 
391 	switch (event) {
392 	case MLX5_DRIVER_EVENT_UPLINK_NETDEV:
393 		if (netdev)
394 			mlx5_dpll_netdev_dpll_pin_set(mdpll, netdev);
395 		else
396 			mlx5_dpll_netdev_dpll_pin_clear(mdpll);
397 		break;
398 	default:
399 		return NOTIFY_DONE;
400 	}
401 
402 	return NOTIFY_OK;
403 }
404 
405 static void mlx5_dpll_mdev_netdev_track(struct mlx5_dpll *mdpll,
406 					struct mlx5_core_dev *mdev)
407 {
408 	mdpll->mdev_nb.notifier_call = mlx5_dpll_mdev_notifier_event;
409 	mlx5_blocking_notifier_register(mdev, &mdpll->mdev_nb);
410 	mlx5_core_uplink_netdev_event_replay(mdev);
411 }
412 
413 static void mlx5_dpll_mdev_netdev_untrack(struct mlx5_dpll *mdpll,
414 					  struct mlx5_core_dev *mdev)
415 {
416 	mlx5_blocking_notifier_unregister(mdev, &mdpll->mdev_nb);
417 	mlx5_dpll_netdev_dpll_pin_clear(mdpll);
418 }
419 
420 static int mlx5_dpll_probe(struct auxiliary_device *adev,
421 			   const struct auxiliary_device_id *id)
422 {
423 	struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
424 	struct mlx5_core_dev *mdev = edev->mdev;
425 	struct mlx5_dpll *mdpll;
426 	u64 clock_id;
427 	int err;
428 
429 	err = mlx5_dpll_synce_status_set(mdev,
430 					 MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING);
431 	if (err)
432 		return err;
433 
434 	err = mlx5_dpll_clock_id_get(mdev, &clock_id);
435 	if (err)
436 		return err;
437 
438 	mdpll = kzalloc_obj(*mdpll);
439 	if (!mdpll)
440 		return -ENOMEM;
441 	mdpll->mdev = mdev;
442 	auxiliary_set_drvdata(adev, mdpll);
443 
444 	/* Multiple mdev instances might share one DPLL device. */
445 	mdpll->dpll = dpll_device_get(clock_id, 0, THIS_MODULE,
446 				      &mdpll->dpll_tracker);
447 	if (IS_ERR(mdpll->dpll)) {
448 		err = PTR_ERR(mdpll->dpll);
449 		goto err_free_mdpll;
450 	}
451 
452 	err = dpll_device_register(mdpll->dpll, DPLL_TYPE_EEC,
453 				   &mlx5_dpll_device_ops, mdpll);
454 	if (err)
455 		goto err_put_dpll_device;
456 
457 	/* Multiple mdev instances might share one DPLL pin. */
458 	mdpll->dpll_pin = dpll_pin_get(clock_id, mlx5_get_dev_index(mdev),
459 				       THIS_MODULE, &mlx5_dpll_pin_properties,
460 				       &mdpll->pin_tracker);
461 	if (IS_ERR(mdpll->dpll_pin)) {
462 		err = PTR_ERR(mdpll->dpll_pin);
463 		goto err_unregister_dpll_device;
464 	}
465 
466 	err = dpll_pin_register(mdpll->dpll, mdpll->dpll_pin,
467 				&mlx5_dpll_pins_ops, mdpll);
468 	if (err)
469 		goto err_put_dpll_pin;
470 
471 	mdpll->wq = create_singlethread_workqueue("mlx5_dpll");
472 	if (!mdpll->wq) {
473 		err = -ENOMEM;
474 		goto err_unregister_dpll_pin;
475 	}
476 
477 	mlx5_dpll_mdev_netdev_track(mdpll, mdev);
478 
479 	INIT_DELAYED_WORK(&mdpll->work, &mlx5_dpll_periodic_work);
480 	mlx5_dpll_periodic_work_queue(mdpll);
481 
482 	return 0;
483 
484 err_unregister_dpll_pin:
485 	dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin,
486 			    &mlx5_dpll_pins_ops, mdpll);
487 err_put_dpll_pin:
488 	dpll_pin_put(mdpll->dpll_pin, &mdpll->pin_tracker);
489 err_unregister_dpll_device:
490 	dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll);
491 err_put_dpll_device:
492 	dpll_device_put(mdpll->dpll, &mdpll->dpll_tracker);
493 err_free_mdpll:
494 	kfree(mdpll);
495 	return err;
496 }
497 
498 static void mlx5_dpll_remove(struct auxiliary_device *adev)
499 {
500 	struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev);
501 	struct mlx5_core_dev *mdev = mdpll->mdev;
502 
503 	cancel_delayed_work_sync(&mdpll->work);
504 	mlx5_dpll_mdev_netdev_untrack(mdpll, mdev);
505 	destroy_workqueue(mdpll->wq);
506 	dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin,
507 			    &mlx5_dpll_pins_ops, mdpll);
508 	dpll_pin_put(mdpll->dpll_pin, &mdpll->pin_tracker);
509 	dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll);
510 	dpll_device_put(mdpll->dpll, &mdpll->dpll_tracker);
511 	kfree(mdpll);
512 
513 	mlx5_dpll_synce_status_set(mdev,
514 				   MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING);
515 }
516 
517 static int mlx5_dpll_suspend(struct auxiliary_device *adev, pm_message_t state)
518 {
519 	return 0;
520 }
521 
522 static int mlx5_dpll_resume(struct auxiliary_device *adev)
523 {
524 	return 0;
525 }
526 
527 static const struct auxiliary_device_id mlx5_dpll_id_table[] = {
528 	{ .name = MLX5_ADEV_NAME ".dpll", },
529 	{},
530 };
531 
532 MODULE_DEVICE_TABLE(auxiliary, mlx5_dpll_id_table);
533 
534 static struct auxiliary_driver mlx5_dpll_driver = {
535 	.name = "dpll",
536 	.probe = mlx5_dpll_probe,
537 	.remove = mlx5_dpll_remove,
538 	.suspend = mlx5_dpll_suspend,
539 	.resume = mlx5_dpll_resume,
540 	.id_table = mlx5_dpll_id_table,
541 };
542 
543 static int __init mlx5_dpll_init(void)
544 {
545 	return auxiliary_driver_register(&mlx5_dpll_driver);
546 }
547 
548 static void __exit mlx5_dpll_exit(void)
549 {
550 	auxiliary_driver_unregister(&mlx5_dpll_driver);
551 }
552 
553 module_init(mlx5_dpll_init);
554 module_exit(mlx5_dpll_exit);
555 
556 MODULE_AUTHOR("Jiri Pirko <jiri@nvidia.com>");
557 MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) DPLL driver");
558 MODULE_LICENSE("Dual BSD/GPL");
559