ionic: pull hwstamp queue_lock up a level
[linux-2.6-microblaze.git] / drivers / net / ethernet / pensando / ionic / ionic_phc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2017 - 2021 Pensando Systems, Inc */
3
4 #include <linux/netdevice.h>
5 #include <linux/etherdevice.h>
6
7 #include "ionic.h"
8 #include "ionic_bus.h"
9 #include "ionic_lif.h"
10 #include "ionic_ethtool.h"
11
12 static int ionic_hwstamp_tx_mode(int config_tx_type)
13 {
14         switch (config_tx_type) {
15         case HWTSTAMP_TX_OFF:
16                 return IONIC_TXSTAMP_OFF;
17         case HWTSTAMP_TX_ON:
18                 return IONIC_TXSTAMP_ON;
19         case HWTSTAMP_TX_ONESTEP_SYNC:
20                 return IONIC_TXSTAMP_ONESTEP_SYNC;
21         case HWTSTAMP_TX_ONESTEP_P2P:
22                 return IONIC_TXSTAMP_ONESTEP_P2P;
23         default:
24                 return -ERANGE;
25         }
26 }
27
28 static u64 ionic_hwstamp_rx_filt(int config_rx_filter)
29 {
30         switch (config_rx_filter) {
31         case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
32                 return IONIC_PKT_CLS_PTP1_ALL;
33         case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
34                 return IONIC_PKT_CLS_PTP1_SYNC;
35         case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
36                 return IONIC_PKT_CLS_PTP1_SYNC | IONIC_PKT_CLS_PTP1_DREQ;
37
38         case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
39                 return IONIC_PKT_CLS_PTP2_L4_ALL;
40         case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
41                 return IONIC_PKT_CLS_PTP2_L4_SYNC;
42         case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
43                 return IONIC_PKT_CLS_PTP2_L4_SYNC | IONIC_PKT_CLS_PTP2_L4_DREQ;
44
45         case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
46                 return IONIC_PKT_CLS_PTP2_L2_ALL;
47         case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
48                 return IONIC_PKT_CLS_PTP2_L2_SYNC;
49         case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
50                 return IONIC_PKT_CLS_PTP2_L2_SYNC | IONIC_PKT_CLS_PTP2_L2_DREQ;
51
52         case HWTSTAMP_FILTER_PTP_V2_EVENT:
53                 return IONIC_PKT_CLS_PTP2_ALL;
54         case HWTSTAMP_FILTER_PTP_V2_SYNC:
55                 return IONIC_PKT_CLS_PTP2_SYNC;
56         case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
57                 return IONIC_PKT_CLS_PTP2_SYNC | IONIC_PKT_CLS_PTP2_DREQ;
58
59         case HWTSTAMP_FILTER_NTP_ALL:
60                 return IONIC_PKT_CLS_NTP_ALL;
61
62         default:
63                 return 0;
64         }
65 }
66
67 static int ionic_lif_hwstamp_set_ts_config(struct ionic_lif *lif,
68                                            struct hwtstamp_config *new_ts)
69 {
70         struct ionic *ionic = lif->ionic;
71         struct hwtstamp_config *config;
72         struct hwtstamp_config ts;
73         int tx_mode = 0;
74         u64 rx_filt = 0;
75         int err, err2;
76         bool rx_all;
77         __le64 mask;
78
79         if (!lif->phc || !lif->phc->ptp)
80                 return -EOPNOTSUPP;
81
82         mutex_lock(&lif->phc->config_lock);
83
84         if (new_ts) {
85                 config = new_ts;
86         } else {
87                 /* If called with new_ts == NULL, replay the previous request
88                  * primarily for recovery after a FW_RESET.
89                  * We saved the previous configuration request info, so copy
90                  * the previous request for reference, clear the current state
91                  * to match the device's reset state, and run with it.
92                  */
93                 config = &ts;
94                 memcpy(config, &lif->phc->ts_config, sizeof(*config));
95                 memset(&lif->phc->ts_config, 0, sizeof(lif->phc->ts_config));
96                 lif->phc->ts_config_tx_mode = 0;
97                 lif->phc->ts_config_rx_filt = 0;
98         }
99
100         tx_mode = ionic_hwstamp_tx_mode(config->tx_type);
101         if (tx_mode < 0) {
102                 err = tx_mode;
103                 goto err_queues;
104         }
105
106         mask = cpu_to_le64(BIT_ULL(tx_mode));
107         if ((ionic->ident.lif.eth.hwstamp_tx_modes & mask) != mask) {
108                 err = -ERANGE;
109                 goto err_queues;
110         }
111
112         rx_filt = ionic_hwstamp_rx_filt(config->rx_filter);
113         rx_all = config->rx_filter != HWTSTAMP_FILTER_NONE && !rx_filt;
114
115         mask = cpu_to_le64(rx_filt);
116         if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) != mask) {
117                 rx_filt = 0;
118                 rx_all = true;
119                 config->rx_filter = HWTSTAMP_FILTER_ALL;
120         }
121
122         dev_dbg(ionic->dev, "%s: config_rx_filter %d rx_filt %#llx rx_all %d\n",
123                 __func__, config->rx_filter, rx_filt, rx_all);
124
125         if (tx_mode) {
126                 err = ionic_lif_create_hwstamp_txq(lif);
127                 if (err)
128                         goto err_queues;
129         }
130
131         if (rx_filt) {
132                 err = ionic_lif_create_hwstamp_rxq(lif);
133                 if (err)
134                         goto err_queues;
135         }
136
137         if (tx_mode != lif->phc->ts_config_tx_mode) {
138                 err = ionic_lif_set_hwstamp_txmode(lif, tx_mode);
139                 if (err)
140                         goto err_txmode;
141         }
142
143         if (rx_filt != lif->phc->ts_config_rx_filt) {
144                 err = ionic_lif_set_hwstamp_rxfilt(lif, rx_filt);
145                 if (err)
146                         goto err_rxfilt;
147         }
148
149         if (rx_all != (lif->phc->ts_config.rx_filter == HWTSTAMP_FILTER_ALL)) {
150                 err = ionic_lif_config_hwstamp_rxq_all(lif, rx_all);
151                 if (err)
152                         goto err_rxall;
153         }
154
155         memcpy(&lif->phc->ts_config, config, sizeof(*config));
156         lif->phc->ts_config_rx_filt = rx_filt;
157         lif->phc->ts_config_tx_mode = tx_mode;
158
159         mutex_unlock(&lif->phc->config_lock);
160
161         return 0;
162
163 err_rxall:
164         if (rx_filt != lif->phc->ts_config_rx_filt) {
165                 rx_filt = lif->phc->ts_config_rx_filt;
166                 err2 = ionic_lif_set_hwstamp_rxfilt(lif, rx_filt);
167                 if (err2)
168                         dev_err(ionic->dev,
169                                 "Failed to revert rx timestamp filter: %d\n", err2);
170         }
171 err_rxfilt:
172         if (tx_mode != lif->phc->ts_config_tx_mode) {
173                 tx_mode = lif->phc->ts_config_tx_mode;
174                 err2 = ionic_lif_set_hwstamp_txmode(lif, tx_mode);
175                 if (err2)
176                         dev_err(ionic->dev,
177                                 "Failed to revert tx timestamp mode: %d\n", err2);
178         }
179 err_txmode:
180         /* special queues remain allocated, just unused */
181 err_queues:
182         mutex_unlock(&lif->phc->config_lock);
183         return err;
184 }
185
186 int ionic_lif_hwstamp_set(struct ionic_lif *lif, struct ifreq *ifr)
187 {
188         struct hwtstamp_config config;
189         int err;
190
191         if (!lif->phc || !lif->phc->ptp)
192                 return -EOPNOTSUPP;
193
194         if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
195                 return -EFAULT;
196
197         mutex_lock(&lif->queue_lock);
198         err = ionic_lif_hwstamp_set_ts_config(lif, &config);
199         mutex_unlock(&lif->queue_lock);
200         if (err) {
201                 netdev_info(lif->netdev, "hwstamp set failed: %d\n", err);
202                 return err;
203         }
204
205         if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
206                 return -EFAULT;
207
208         return 0;
209 }
210
211 void ionic_lif_hwstamp_replay(struct ionic_lif *lif)
212 {
213         int err;
214
215         if (!lif->phc || !lif->phc->ptp)
216                 return;
217
218         mutex_lock(&lif->queue_lock);
219         err = ionic_lif_hwstamp_set_ts_config(lif, NULL);
220         mutex_unlock(&lif->queue_lock);
221         if (err)
222                 netdev_info(lif->netdev, "hwstamp replay failed: %d\n", err);
223 }
224
225 int ionic_lif_hwstamp_get(struct ionic_lif *lif, struct ifreq *ifr)
226 {
227         struct hwtstamp_config config;
228
229         if (!lif->phc || !lif->phc->ptp)
230                 return -EOPNOTSUPP;
231
232         mutex_lock(&lif->phc->config_lock);
233         memcpy(&config, &lif->phc->ts_config, sizeof(config));
234         mutex_unlock(&lif->phc->config_lock);
235
236         if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
237                 return -EFAULT;
238         return 0;
239 }
240
241 static u64 ionic_hwstamp_read(struct ionic *ionic,
242                               struct ptp_system_timestamp *sts)
243 {
244         u32 tick_high_before, tick_high, tick_low;
245
246         /* read and discard low part to defeat hw staging of high part */
247         (void)ioread32(&ionic->idev.hwstamp_regs->tick_low);
248
249         tick_high_before = ioread32(&ionic->idev.hwstamp_regs->tick_high);
250
251         ptp_read_system_prets(sts);
252         tick_low = ioread32(&ionic->idev.hwstamp_regs->tick_low);
253         ptp_read_system_postts(sts);
254
255         tick_high = ioread32(&ionic->idev.hwstamp_regs->tick_high);
256
257         /* If tick_high changed, re-read tick_low once more.  Assume tick_high
258          * cannot change again so soon as in the span of re-reading tick_low.
259          */
260         if (tick_high != tick_high_before) {
261                 ptp_read_system_prets(sts);
262                 tick_low = ioread32(&ionic->idev.hwstamp_regs->tick_low);
263                 ptp_read_system_postts(sts);
264         }
265
266         return (u64)tick_low | ((u64)tick_high << 32);
267 }
268
269 static u64 ionic_cc_read(const struct cyclecounter *cc)
270 {
271         struct ionic_phc *phc = container_of(cc, struct ionic_phc, cc);
272         struct ionic *ionic = phc->lif->ionic;
273
274         return ionic_hwstamp_read(ionic, NULL);
275 }
276
277 static int ionic_setphc_cmd(struct ionic_phc *phc, struct ionic_admin_ctx *ctx)
278 {
279         ctx->work = COMPLETION_INITIALIZER_ONSTACK(ctx->work);
280
281         ctx->cmd.lif_setphc.opcode = IONIC_CMD_LIF_SETPHC;
282         ctx->cmd.lif_setphc.lif_index = cpu_to_le16(phc->lif->index);
283
284         ctx->cmd.lif_setphc.tick = cpu_to_le64(phc->tc.cycle_last);
285         ctx->cmd.lif_setphc.nsec = cpu_to_le64(phc->tc.nsec);
286         ctx->cmd.lif_setphc.frac = cpu_to_le64(phc->tc.frac);
287         ctx->cmd.lif_setphc.mult = cpu_to_le32(phc->cc.mult);
288         ctx->cmd.lif_setphc.shift = cpu_to_le32(phc->cc.shift);
289
290         return ionic_adminq_post(phc->lif, ctx);
291 }
292
293 static int ionic_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
294 {
295         struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
296         struct ionic_admin_ctx ctx = {};
297         unsigned long irqflags;
298         s64 adj;
299         int err;
300
301         /* Reject phc adjustments during device upgrade */
302         if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state))
303                 return -EBUSY;
304
305         /* Adjustment value scaled by 2^16 million */
306         adj = (s64)scaled_ppm * phc->init_cc_mult;
307
308         /* Adjustment value to scale */
309         adj /= (s64)SCALED_PPM;
310
311         /* Final adjusted multiplier */
312         adj += phc->init_cc_mult;
313
314         spin_lock_irqsave(&phc->lock, irqflags);
315
316         /* update the point-in-time basis to now, before adjusting the rate */
317         timecounter_read(&phc->tc);
318         phc->cc.mult = adj;
319
320         /* Setphc commands are posted in-order, sequenced by phc->lock.  We
321          * need to drop the lock before waiting for the command to complete.
322          */
323         err = ionic_setphc_cmd(phc, &ctx);
324
325         spin_unlock_irqrestore(&phc->lock, irqflags);
326
327         return ionic_adminq_wait(phc->lif, &ctx, err);
328 }
329
330 static int ionic_phc_adjtime(struct ptp_clock_info *info, s64 delta)
331 {
332         struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
333         struct ionic_admin_ctx ctx = {};
334         unsigned long irqflags;
335         int err;
336
337         /* Reject phc adjustments during device upgrade */
338         if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state))
339                 return -EBUSY;
340
341         spin_lock_irqsave(&phc->lock, irqflags);
342
343         timecounter_adjtime(&phc->tc, delta);
344
345         /* Setphc commands are posted in-order, sequenced by phc->lock.  We
346          * need to drop the lock before waiting for the command to complete.
347          */
348         err = ionic_setphc_cmd(phc, &ctx);
349
350         spin_unlock_irqrestore(&phc->lock, irqflags);
351
352         return ionic_adminq_wait(phc->lif, &ctx, err);
353 }
354
355 static int ionic_phc_settime64(struct ptp_clock_info *info,
356                                const struct timespec64 *ts)
357 {
358         struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
359         struct ionic_admin_ctx ctx = {};
360         unsigned long irqflags;
361         int err;
362         u64 ns;
363
364         /* Reject phc adjustments during device upgrade */
365         if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state))
366                 return -EBUSY;
367
368         ns = timespec64_to_ns(ts);
369
370         spin_lock_irqsave(&phc->lock, irqflags);
371
372         timecounter_init(&phc->tc, &phc->cc, ns);
373
374         /* Setphc commands are posted in-order, sequenced by phc->lock.  We
375          * need to drop the lock before waiting for the command to complete.
376          */
377         err = ionic_setphc_cmd(phc, &ctx);
378
379         spin_unlock_irqrestore(&phc->lock, irqflags);
380
381         return ionic_adminq_wait(phc->lif, &ctx, err);
382 }
383
384 static int ionic_phc_gettimex64(struct ptp_clock_info *info,
385                                 struct timespec64 *ts,
386                                 struct ptp_system_timestamp *sts)
387 {
388         struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
389         struct ionic *ionic = phc->lif->ionic;
390         unsigned long irqflags;
391         u64 tick, ns;
392
393         /* Do not attempt to read device time during upgrade */
394         if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state))
395                 return -EBUSY;
396
397         spin_lock_irqsave(&phc->lock, irqflags);
398
399         tick = ionic_hwstamp_read(ionic, sts);
400
401         ns = timecounter_cyc2time(&phc->tc, tick);
402
403         spin_unlock_irqrestore(&phc->lock, irqflags);
404
405         *ts = ns_to_timespec64(ns);
406
407         return 0;
408 }
409
410 static long ionic_phc_aux_work(struct ptp_clock_info *info)
411 {
412         struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
413         struct ionic_admin_ctx ctx = {};
414         unsigned long irqflags;
415         int err;
416
417         /* Do not update phc during device upgrade, but keep polling to resume
418          * after upgrade.  Since we don't update the point in time basis, there
419          * is no expectation that we are maintaining the phc time during the
420          * upgrade.  After upgrade, it will need to be readjusted back to the
421          * correct time by the ptp daemon.
422          */
423         if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state))
424                 return phc->aux_work_delay;
425
426         spin_lock_irqsave(&phc->lock, irqflags);
427
428         /* update point-in-time basis to now */
429         timecounter_read(&phc->tc);
430
431         /* Setphc commands are posted in-order, sequenced by phc->lock.  We
432          * need to drop the lock before waiting for the command to complete.
433          */
434         err = ionic_setphc_cmd(phc, &ctx);
435
436         spin_unlock_irqrestore(&phc->lock, irqflags);
437
438         ionic_adminq_wait(phc->lif, &ctx, err);
439
440         return phc->aux_work_delay;
441 }
442
443 ktime_t ionic_lif_phc_ktime(struct ionic_lif *lif, u64 tick)
444 {
445         unsigned long irqflags;
446         u64 ns;
447
448         if (!lif->phc)
449                 return 0;
450
451         spin_lock_irqsave(&lif->phc->lock, irqflags);
452         ns = timecounter_cyc2time(&lif->phc->tc, tick);
453         spin_unlock_irqrestore(&lif->phc->lock, irqflags);
454
455         return ns_to_ktime(ns);
456 }
457
458 static const struct ptp_clock_info ionic_ptp_info = {
459         .owner          = THIS_MODULE,
460         .name           = "ionic_ptp",
461         .adjfine        = ionic_phc_adjfine,
462         .adjtime        = ionic_phc_adjtime,
463         .gettimex64     = ionic_phc_gettimex64,
464         .settime64      = ionic_phc_settime64,
465         .do_aux_work    = ionic_phc_aux_work,
466 };
467
468 void ionic_lif_register_phc(struct ionic_lif *lif)
469 {
470         if (!lif->phc || !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
471                 return;
472
473         lif->phc->ptp = ptp_clock_register(&lif->phc->ptp_info, lif->ionic->dev);
474
475         if (IS_ERR(lif->phc->ptp)) {
476                 dev_warn(lif->ionic->dev, "Cannot register phc device: %ld\n",
477                          PTR_ERR(lif->phc->ptp));
478
479                 lif->phc->ptp = NULL;
480         }
481
482         if (lif->phc->ptp)
483                 ptp_schedule_worker(lif->phc->ptp, lif->phc->aux_work_delay);
484 }
485
486 void ionic_lif_unregister_phc(struct ionic_lif *lif)
487 {
488         if (!lif->phc || !lif->phc->ptp)
489                 return;
490
491         ptp_clock_unregister(lif->phc->ptp);
492
493         lif->phc->ptp = NULL;
494 }
495
496 void ionic_lif_alloc_phc(struct ionic_lif *lif)
497 {
498         struct ionic *ionic = lif->ionic;
499         struct ionic_phc *phc;
500         u64 delay, diff, mult;
501         u64 frac = 0;
502         u64 features;
503         u32 shift;
504
505         if (!ionic->idev.hwstamp_regs)
506                 return;
507
508         features = le64_to_cpu(ionic->ident.lif.eth.config.features);
509         if (!(features & IONIC_ETH_HW_TIMESTAMP))
510                 return;
511
512         phc = devm_kzalloc(ionic->dev, sizeof(*phc), GFP_KERNEL);
513         if (!phc)
514                 return;
515
516         phc->lif = lif;
517
518         phc->cc.read = ionic_cc_read;
519         phc->cc.mask = le64_to_cpu(ionic->ident.dev.hwstamp_mask);
520         phc->cc.mult = le32_to_cpu(ionic->ident.dev.hwstamp_mult);
521         phc->cc.shift = le32_to_cpu(ionic->ident.dev.hwstamp_shift);
522
523         if (!phc->cc.mult) {
524                 dev_err(lif->ionic->dev,
525                         "Invalid device PHC mask multiplier %u, disabling HW timestamp support\n",
526                         phc->cc.mult);
527                 devm_kfree(lif->ionic->dev, phc);
528                 lif->phc = NULL;
529                 return;
530         }
531
532         dev_dbg(lif->ionic->dev, "Device PHC mask %#llx mult %u shift %u\n",
533                 phc->cc.mask, phc->cc.mult, phc->cc.shift);
534
535         spin_lock_init(&phc->lock);
536         mutex_init(&phc->config_lock);
537
538         /* max ticks is limited by the multiplier, or by the update period. */
539         if (phc->cc.shift + 2 + ilog2(IONIC_PHC_UPDATE_NS) >= 64) {
540                 /* max ticks that do not overflow when multiplied by max
541                  * adjusted multiplier (twice the initial multiplier)
542                  */
543                 diff = U64_MAX / phc->cc.mult / 2;
544         } else {
545                 /* approx ticks at four times the update period */
546                 diff = (u64)IONIC_PHC_UPDATE_NS << (phc->cc.shift + 2);
547                 diff = DIV_ROUND_UP(diff, phc->cc.mult);
548         }
549
550         /* transform to bitmask */
551         diff |= diff >> 1;
552         diff |= diff >> 2;
553         diff |= diff >> 4;
554         diff |= diff >> 8;
555         diff |= diff >> 16;
556         diff |= diff >> 32;
557
558         /* constrain to the hardware bitmask, and use this as the bitmask */
559         diff &= phc->cc.mask;
560         phc->cc.mask = diff;
561
562         /* the wrap period is now defined by diff (or phc->cc.mask)
563          *
564          * we will update the time basis at about 1/4 the wrap period, so
565          * should not see a difference of more than +/- diff/4.
566          *
567          * this is sufficient not see a difference of more than +/- diff/2, as
568          * required by timecounter_cyc2time, to detect an old time stamp.
569          *
570          * adjust the initial multiplier, being careful to avoid overflow:
571          *  - do not overflow 63 bits: init_cc_mult * SCALED_PPM
572          *  - do not overflow 64 bits: max_mult * (diff / 2)
573          *
574          * we want to increase the initial multiplier as much as possible, to
575          * allow for more precise adjustment in ionic_phc_adjfine.
576          *
577          * only adjust the multiplier if we can double it or more.
578          */
579         mult = U64_MAX / 2 / max(diff / 2, SCALED_PPM);
580         shift = mult / phc->cc.mult;
581         if (shift >= 2) {
582                 /* initial multiplier will be 2^n of hardware cc.mult */
583                 shift = fls(shift);
584                 /* increase cc.mult and cc.shift by the same 2^n and n. */
585                 phc->cc.mult <<= shift;
586                 phc->cc.shift += shift;
587         }
588
589         dev_dbg(lif->ionic->dev, "Initial PHC mask %#llx mult %u shift %u\n",
590                 phc->cc.mask, phc->cc.mult, phc->cc.shift);
591
592         /* frequency adjustments are relative to the initial multiplier */
593         phc->init_cc_mult = phc->cc.mult;
594
595         timecounter_init(&phc->tc, &phc->cc, ktime_get_real_ns());
596
597         /* Update cycle_last at 1/4 the wrap period, or IONIC_PHC_UPDATE_NS */
598         delay = min_t(u64, IONIC_PHC_UPDATE_NS,
599                       cyclecounter_cyc2ns(&phc->cc, diff / 4, 0, &frac));
600         dev_dbg(lif->ionic->dev, "Work delay %llu ms\n", delay / NSEC_PER_MSEC);
601
602         phc->aux_work_delay = nsecs_to_jiffies(delay);
603
604         phc->ptp_info = ionic_ptp_info;
605
606         /* We have allowed to adjust the multiplier up to +/- 1 part per 1.
607          * Here expressed as NORMAL_PPB (1 billion parts per billion).
608          */
609         phc->ptp_info.max_adj = NORMAL_PPB;
610
611         lif->phc = phc;
612 }
613
614 void ionic_lif_free_phc(struct ionic_lif *lif)
615 {
616         if (!lif->phc)
617                 return;
618
619         mutex_destroy(&lif->phc->config_lock);
620
621         devm_kfree(lif->ionic->dev, lif->phc);
622         lif->phc = NULL;
623 }