Skip to content

Commit 99620ea

Browse files
committed
Merge branch 'dpll-phase-offset-phase-adjust'
Arkadiusz Kubalewski says: ==================== dpll: add phase-offset and phase-adjust Improve monitoring and control over dpll devices. Allow user to receive measurement of phase difference between signals on pin and dpll (phase-offset). Allow user to receive and control adjustable value of pin's signal phase (phase-adjust). v4->v5: - rebase series on top of net-next/main, fix conflict - remove redundant attribute type definition in subset definition v3->v4: - do not increase do version of uAPI header as it is not needed (v3 did not have this change) - fix spelling around commit messages, argument descriptions and docs - add missing extack errors on failure set callbacks for pin phase adjust and frequency - remove ice check if value is already set, now redundant as checked in the dpll subsystem v2->v3: - do not increase do version of uAPI header as it is not needed v1->v2: - improve handling for error case of requesting the phase adjust set - align handling for error case of frequency set request with the approach introduced for phase adjust ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents cc30c63 + 20f6677 commit 99620ea

File tree

9 files changed

+517
-18
lines changed

9 files changed

+517
-18
lines changed

Documentation/driver-api/dpll.rst

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,47 @@ in order to configure active input of a MUX-type pin, the user needs to
173173
request desired pin state of the child pin on the parent pin,
174174
as described in the ``MUX-type pins`` chapter.
175175

176+
Phase offset measurement and adjustment
177+
========================================
178+
179+
Device may provide ability to measure a phase difference between signals
180+
on a pin and its parent dpll device. If pin-dpll phase offset measurement
181+
is supported, it shall be provided with ``DPLL_A_PIN_PHASE_OFFSET``
182+
attribute for each parent dpll device.
183+
184+
Device may also provide ability to adjust a signal phase on a pin.
185+
If pin phase adjustment is supported, minimal and maximal values that pin
186+
handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond
187+
with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX``
188+
attributes. Configured phase adjust value is provided with
189+
``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be
190+
requested with the same attribute with ``DPLL_CMD_PIN_SET`` command.
191+
192+
=============================== ======================================
193+
``DPLL_A_PIN_ID`` configured pin id
194+
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment
195+
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment
196+
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
197+
adjustment on parent dpll device
198+
``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting
199+
configuration on given parent dpll
200+
device
201+
``DPLL_A_PIN_PARENT_ID`` parent dpll device id
202+
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
203+
between a pin and parent dpll device
204+
=============================== ======================================
205+
206+
All phase related values are provided in pico seconds, which represents
207+
time difference between signals phase. The negative value means that
208+
phase of signal on pin is earlier in time than dpll's signal. Positive
209+
value means that phase of signal on pin is later in time than signal of
210+
a dpll.
211+
212+
Phase adjust (also min and max) values are integers, but measured phase
213+
offset values are fractional with 3-digit decimal places and shell be
214+
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
215+
modulo divided to get fractional part.
216+
176217
Configuration commands group
177218
============================
178219

@@ -263,15 +304,23 @@ according to attribute purpose.
263304
frequencies
264305
``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency
265306
``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency
307+
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase
308+
adjustment
309+
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase
310+
adjustment
311+
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
312+
adjustment on parent device
266313
``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device
267314
the pin is connected with
268315
``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
269316
``DPLL_A_PIN_PRIO`` attr priority of pin on the
270317
dpll device
271318
``DPLL_A_PIN_STATE`` attr state of pin on the parent
272319
dpll device
273-
``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
320+
``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
274321
parent dpll device
322+
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
323+
between a pin and parent dpll
275324
``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
276325
the pin is connected with
277326
``DPLL_A_PIN_PARENT_ID`` attr parent pin id
@@ -284,6 +333,8 @@ according to attribute purpose.
284333
``DPLL_CMD_PIN_SET`` command to set pins configuration
285334
``DPLL_A_PIN_ID`` attr unique a pin ID
286335
``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin
336+
``DPLL_A_PIN_PHASE_ADJUST`` attr requested value of phase
337+
adjustment on parent device
287338
``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll
288339
device configuration request
289340
``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id

Documentation/netlink/specs/dpll.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@ definitions:
164164
-
165165
name: state-can-change
166166
doc: pin state can be changed
167+
-
168+
type: const
169+
name: phase-offset-divider
170+
value: 1000
171+
doc: |
172+
phase offset divider allows userspace to calculate a value of
173+
measured signal phase difference between a pin and dpll device
174+
as a fractional value with three digit decimal precision.
175+
Value of (DPLL_A_PHASE_OFFSET / DPLL_PHASE_OFFSET_DIVIDER) is an
176+
integer part of a measured phase offset value.
177+
Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
178+
fractional part of a measured phase offset value.
167179
168180
attribute-sets:
169181
-
@@ -272,6 +284,18 @@ attribute-sets:
272284
type: nest
273285
multi-attr: true
274286
nested-attributes: pin-parent-pin
287+
-
288+
name: phase-adjust-min
289+
type: s32
290+
-
291+
name: phase-adjust-max
292+
type: s32
293+
-
294+
name: phase-adjust
295+
type: s32
296+
-
297+
name: phase-offset
298+
type: s64
275299
-
276300
name: pin-parent-device
277301
subset-of: pin
@@ -284,6 +308,8 @@ attribute-sets:
284308
name: prio
285309
-
286310
name: state
311+
-
312+
name: phase-offset
287313
-
288314
name: pin-parent-pin
289315
subset-of: pin
@@ -431,6 +457,9 @@ operations:
431457
- capabilities
432458
- parent-device
433459
- parent-pin
460+
- phase-adjust-min
461+
- phase-adjust-max
462+
- phase-adjust
434463

435464
dump:
436465
pre: dpll-lock-dumpit
@@ -458,6 +487,7 @@ operations:
458487
- state
459488
- parent-device
460489
- parent-pin
490+
- phase-adjust
461491
-
462492
name: pin-create-ntf
463493
doc: Notification about pin appearing

drivers/dpll/dpll_netlink.c

Lines changed: 179 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,53 @@ dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
212212
return 0;
213213
}
214214

215+
static int
216+
dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin,
217+
struct dpll_pin_ref *ref,
218+
struct netlink_ext_ack *extack)
219+
{
220+
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
221+
struct dpll_device *dpll = ref->dpll;
222+
s32 phase_adjust;
223+
int ret;
224+
225+
if (!ops->phase_adjust_get)
226+
return 0;
227+
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
228+
dpll, dpll_priv(dpll),
229+
&phase_adjust, extack);
230+
if (ret)
231+
return ret;
232+
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust))
233+
return -EMSGSIZE;
234+
235+
return 0;
236+
}
237+
238+
static int
239+
dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
240+
struct dpll_pin_ref *ref,
241+
struct netlink_ext_ack *extack)
242+
{
243+
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
244+
struct dpll_device *dpll = ref->dpll;
245+
s64 phase_offset;
246+
int ret;
247+
248+
if (!ops->phase_offset_get)
249+
return 0;
250+
ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
251+
dpll, dpll_priv(dpll), &phase_offset,
252+
extack);
253+
if (ret)
254+
return ret;
255+
if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset),
256+
&phase_offset, DPLL_A_PIN_PAD))
257+
return -EMSGSIZE;
258+
259+
return 0;
260+
}
261+
215262
static int
216263
dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
217264
struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
@@ -330,6 +377,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
330377
if (ret)
331378
goto nest_cancel;
332379
ret = dpll_msg_add_pin_direction(msg, pin, ref, extack);
380+
if (ret)
381+
goto nest_cancel;
382+
ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
333383
if (ret)
334384
goto nest_cancel;
335385
nla_nest_end(msg, attr);
@@ -377,6 +427,15 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
377427
if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities))
378428
return -EMSGSIZE;
379429
ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
430+
if (ret)
431+
return ret;
432+
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
433+
prop->phase_range.min))
434+
return -EMSGSIZE;
435+
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX,
436+
prop->phase_range.max))
437+
return -EMSGSIZE;
438+
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
380439
if (ret)
381440
return ret;
382441
if (xa_empty(&pin->parent_refs))
@@ -416,7 +475,7 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
416475
if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
417476
return -EMSGSIZE;
418477

419-
return ret;
478+
return 0;
420479
}
421480

422481
static int
@@ -556,8 +615,10 @@ static int
556615
dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
557616
struct netlink_ext_ack *extack)
558617
{
559-
u64 freq = nla_get_u64(a);
560-
struct dpll_pin_ref *ref;
618+
u64 freq = nla_get_u64(a), old_freq;
619+
struct dpll_pin_ref *ref, *failed;
620+
const struct dpll_pin_ops *ops;
621+
struct dpll_device *dpll;
561622
unsigned long i;
562623
int ret;
563624

@@ -567,19 +628,51 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
567628
}
568629

569630
xa_for_each(&pin->dpll_refs, i, ref) {
570-
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
571-
struct dpll_device *dpll = ref->dpll;
572-
573-
if (!ops->frequency_set)
631+
ops = dpll_pin_ops(ref);
632+
if (!ops->frequency_set || !ops->frequency_get) {
633+
NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
574634
return -EOPNOTSUPP;
635+
}
636+
}
637+
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
638+
ops = dpll_pin_ops(ref);
639+
dpll = ref->dpll;
640+
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
641+
dpll_priv(dpll), &old_freq, extack);
642+
if (ret) {
643+
NL_SET_ERR_MSG(extack, "unable to get old frequency value");
644+
return ret;
645+
}
646+
if (freq == old_freq)
647+
return 0;
648+
649+
xa_for_each(&pin->dpll_refs, i, ref) {
650+
ops = dpll_pin_ops(ref);
651+
dpll = ref->dpll;
575652
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
576653
dpll, dpll_priv(dpll), freq, extack);
577-
if (ret)
578-
return ret;
654+
if (ret) {
655+
failed = ref;
656+
NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u",
657+
dpll->id);
658+
goto rollback;
659+
}
579660
}
580661
__dpll_pin_change_ntf(pin);
581662

582663
return 0;
664+
665+
rollback:
666+
xa_for_each(&pin->dpll_refs, i, ref) {
667+
if (ref == failed)
668+
break;
669+
ops = dpll_pin_ops(ref);
670+
dpll = ref->dpll;
671+
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
672+
dpll, dpll_priv(dpll), old_freq, extack))
673+
NL_SET_ERR_MSG(extack, "set frequency rollback failed");
674+
}
675+
return ret;
583676
}
584677

585678
static int
@@ -705,6 +798,78 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
705798
return 0;
706799
}
707800

801+
static int
802+
dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
803+
struct netlink_ext_ack *extack)
804+
{
805+
struct dpll_pin_ref *ref, *failed;
806+
const struct dpll_pin_ops *ops;
807+
s32 phase_adj, old_phase_adj;
808+
struct dpll_device *dpll;
809+
unsigned long i;
810+
int ret;
811+
812+
phase_adj = nla_get_s32(phase_adj_attr);
813+
if (phase_adj > pin->prop->phase_range.max ||
814+
phase_adj < pin->prop->phase_range.min) {
815+
NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
816+
"phase adjust value not supported");
817+
return -EINVAL;
818+
}
819+
820+
xa_for_each(&pin->dpll_refs, i, ref) {
821+
ops = dpll_pin_ops(ref);
822+
if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
823+
NL_SET_ERR_MSG(extack, "phase adjust not supported");
824+
return -EOPNOTSUPP;
825+
}
826+
}
827+
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
828+
ops = dpll_pin_ops(ref);
829+
dpll = ref->dpll;
830+
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
831+
dpll, dpll_priv(dpll), &old_phase_adj,
832+
extack);
833+
if (ret) {
834+
NL_SET_ERR_MSG(extack, "unable to get old phase adjust value");
835+
return ret;
836+
}
837+
if (phase_adj == old_phase_adj)
838+
return 0;
839+
840+
xa_for_each(&pin->dpll_refs, i, ref) {
841+
ops = dpll_pin_ops(ref);
842+
dpll = ref->dpll;
843+
ret = ops->phase_adjust_set(pin,
844+
dpll_pin_on_dpll_priv(dpll, pin),
845+
dpll, dpll_priv(dpll), phase_adj,
846+
extack);
847+
if (ret) {
848+
failed = ref;
849+
NL_SET_ERR_MSG_FMT(extack,
850+
"phase adjust set failed for dpll_id:%u",
851+
dpll->id);
852+
goto rollback;
853+
}
854+
}
855+
__dpll_pin_change_ntf(pin);
856+
857+
return 0;
858+
859+
rollback:
860+
xa_for_each(&pin->dpll_refs, i, ref) {
861+
if (ref == failed)
862+
break;
863+
ops = dpll_pin_ops(ref);
864+
dpll = ref->dpll;
865+
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
866+
dpll, dpll_priv(dpll), old_phase_adj,
867+
extack))
868+
NL_SET_ERR_MSG(extack, "set phase adjust rollback failed");
869+
}
870+
return ret;
871+
}
872+
708873
static int
709874
dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
710875
struct netlink_ext_ack *extack)
@@ -793,6 +958,11 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
793958
if (ret)
794959
return ret;
795960
break;
961+
case DPLL_A_PIN_PHASE_ADJUST:
962+
ret = dpll_pin_phase_adj_set(pin, a, info->extack);
963+
if (ret)
964+
return ret;
965+
break;
796966
case DPLL_A_PIN_PARENT_DEVICE:
797967
ret = dpll_pin_parent_device_set(pin, a, info->extack);
798968
if (ret)

0 commit comments

Comments
 (0)