1 // SPDX-License-Identifier: GPL-2.0
3 * Generic netlink for DPLL management framework
5 * Copyright (c) 2023 Meta Platforms, Inc. and affiliates
6 * Copyright (c) 2023 Intel and affiliates
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <net/genetlink.h>
12 #include "dpll_core.h"
13 #include "dpll_netlink.h"
15 #include <uapi/linux/dpll.h>
17 #define ASSERT_NOT_NULL(ptr) (WARN_ON(!ptr))
19 #define xa_for_each_marked_start(xa, index, entry, filter, start) \
20 for (index = start, entry = xa_find(xa, &index, ULONG_MAX, filter); \
21 entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter))
23 struct dpll_dump_ctx {
27 static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb)
29 return (struct dpll_dump_ctx *)cb->ctx;
33 dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll)
35 if (nla_put_u32(msg, DPLL_A_ID, dpll->id))
42 dpll_msg_add_dev_parent_handle(struct sk_buff *msg, u32 id)
44 if (nla_put_u32(msg, DPLL_A_PIN_PARENT_ID, id))
51 * dpll_msg_pin_handle_size - get size of pin handle attribute for given pin
54 * Return: byte size of pin handle attribute for given pin.
56 size_t dpll_msg_pin_handle_size(struct dpll_pin *pin)
58 return pin ? nla_total_size(4) : 0; /* DPLL_A_PIN_ID */
60 EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size);
63 * dpll_msg_add_pin_handle - attach pin handle attribute to a given message
64 * @msg: pointer to sk_buff message to attach a pin handle
69 * * -EMSGSIZE - no space in message to attach pin handle
71 int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin)
75 if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id))
79 EXPORT_SYMBOL_GPL(dpll_msg_add_pin_handle);
82 dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll,
83 struct netlink_ext_ack *extack)
85 const struct dpll_device_ops *ops = dpll_device_ops(dpll);
89 ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
92 if (nla_put_u32(msg, DPLL_A_MODE, mode))
99 dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll,
100 struct netlink_ext_ack *extack)
102 const struct dpll_device_ops *ops = dpll_device_ops(dpll);
106 /* No mode change is supported now, so the only supported mode is the
107 * one obtained by mode_get().
110 ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack);
113 if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode))
120 dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll,
121 struct netlink_ext_ack *extack)
123 const struct dpll_device_ops *ops = dpll_device_ops(dpll);
124 enum dpll_lock_status status;
127 ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack);
130 if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status))
137 dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
138 struct netlink_ext_ack *extack)
140 const struct dpll_device_ops *ops = dpll_device_ops(dpll);
146 ret = ops->temp_get(dpll, dpll_priv(dpll), &temp, extack);
149 if (nla_put_s32(msg, DPLL_A_TEMP, temp))
156 dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
157 struct dpll_pin_ref *ref,
158 struct netlink_ext_ack *extack)
160 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
161 struct dpll_device *dpll = ref->dpll;
167 ret = ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
168 dpll_priv(dpll), &prio, extack);
171 if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio))
178 dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin,
179 struct dpll_pin_ref *ref,
180 struct netlink_ext_ack *extack)
182 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
183 struct dpll_device *dpll = ref->dpll;
184 enum dpll_pin_state state;
187 if (!ops->state_on_dpll_get)
189 ret = ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
190 dpll, dpll_priv(dpll), &state, extack);
193 if (nla_put_u32(msg, DPLL_A_PIN_STATE, state))
200 dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
201 struct dpll_pin_ref *ref,
202 struct netlink_ext_ack *extack)
204 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
205 struct dpll_device *dpll = ref->dpll;
206 enum dpll_pin_direction direction;
209 ret = ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
210 dpll_priv(dpll), &direction, extack);
213 if (nla_put_u32(msg, DPLL_A_PIN_DIRECTION, direction))
220 dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin,
221 struct dpll_pin_ref *ref,
222 struct netlink_ext_ack *extack)
224 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
225 struct dpll_device *dpll = ref->dpll;
229 if (!ops->phase_adjust_get)
231 ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
232 dpll, dpll_priv(dpll),
233 &phase_adjust, extack);
236 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust))
243 dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
244 struct dpll_pin_ref *ref,
245 struct netlink_ext_ack *extack)
247 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
248 struct dpll_device *dpll = ref->dpll;
252 if (!ops->phase_offset_get)
254 ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
255 dpll, dpll_priv(dpll), &phase_offset,
259 if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset),
260 &phase_offset, DPLL_A_PIN_PAD))
267 dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
268 struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
270 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
271 struct dpll_device *dpll = ref->dpll;
276 if (!ops->frequency_get)
278 ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
279 dpll_priv(dpll), &freq, extack);
282 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq,
285 for (fs = 0; fs < pin->prop->freq_supported_num; fs++) {
286 nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED);
289 freq = pin->prop->freq_supported[fs].min;
290 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq),
291 &freq, DPLL_A_PIN_PAD)) {
292 nla_nest_cancel(msg, nest);
295 freq = pin->prop->freq_supported[fs].max;
296 if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq),
297 &freq, DPLL_A_PIN_PAD)) {
298 nla_nest_cancel(msg, nest);
301 nla_nest_end(msg, nest);
307 static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
311 for (fs = 0; fs < pin->prop->freq_supported_num; fs++)
312 if (freq >= pin->prop->freq_supported[fs].min &&
313 freq <= pin->prop->freq_supported[fs].max)
319 dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin,
320 struct dpll_pin_ref *dpll_ref,
321 struct netlink_ext_ack *extack)
323 enum dpll_pin_state state;
324 struct dpll_pin_ref *ref;
325 struct dpll_pin *ppin;
330 xa_for_each(&pin->parent_refs, index, ref) {
331 const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
335 parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin);
336 ret = ops->state_on_pin_get(pin,
337 dpll_pin_on_pin_priv(ppin, pin),
338 ppin, parent_priv, &state, extack);
341 nest = nla_nest_start(msg, DPLL_A_PIN_PARENT_PIN);
344 ret = dpll_msg_add_dev_parent_handle(msg, ppin->id);
347 if (nla_put_u32(msg, DPLL_A_PIN_STATE, state)) {
351 nla_nest_end(msg, nest);
357 nla_nest_cancel(msg, nest);
362 dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
363 struct netlink_ext_ack *extack)
365 struct dpll_pin_ref *ref;
370 xa_for_each(&pin->dpll_refs, index, ref) {
371 attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
374 ret = dpll_msg_add_dev_parent_handle(msg, ref->dpll->id);
377 ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack);
380 ret = dpll_msg_add_pin_prio(msg, pin, ref, extack);
383 ret = dpll_msg_add_pin_direction(msg, pin, ref, extack);
386 ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
389 nla_nest_end(msg, attr);
395 nla_nest_end(msg, attr);
400 dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
401 struct netlink_ext_ack *extack)
403 const struct dpll_pin_properties *prop = pin->prop;
404 struct dpll_pin_ref *ref;
407 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
408 ASSERT_NOT_NULL(ref);
410 ret = dpll_msg_add_pin_handle(msg, pin);
413 if (nla_put_string(msg, DPLL_A_PIN_MODULE_NAME,
414 module_name(pin->module)))
416 if (nla_put_64bit(msg, DPLL_A_PIN_CLOCK_ID, sizeof(pin->clock_id),
417 &pin->clock_id, DPLL_A_PIN_PAD))
419 if (prop->board_label &&
420 nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label))
422 if (prop->panel_label &&
423 nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label))
425 if (prop->package_label &&
426 nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL,
427 prop->package_label))
429 if (nla_put_u32(msg, DPLL_A_PIN_TYPE, prop->type))
431 if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities))
433 ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
436 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
437 prop->phase_range.min))
439 if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX,
440 prop->phase_range.max))
442 ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
445 if (xa_empty(&pin->parent_refs))
446 ret = dpll_msg_add_pin_dplls(msg, pin, extack);
448 ret = dpll_msg_add_pin_parents(msg, pin, ref, extack);
454 dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
455 struct netlink_ext_ack *extack)
459 ret = dpll_msg_add_dev_handle(msg, dpll);
462 if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module)))
464 if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id),
465 &dpll->clock_id, DPLL_A_PAD))
467 ret = dpll_msg_add_temp(msg, dpll, extack);
470 ret = dpll_msg_add_lock_status(msg, dpll, extack);
473 ret = dpll_msg_add_mode(msg, dpll, extack);
476 ret = dpll_msg_add_mode_supported(msg, dpll, extack);
479 if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
486 dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll)
492 if (WARN_ON(!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED)))
494 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
497 hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
500 ret = dpll_device_get_one(dpll, msg, NULL);
503 genlmsg_end(msg, hdr);
504 genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
509 genlmsg_cancel(msg, hdr);
516 int dpll_device_create_ntf(struct dpll_device *dpll)
518 return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll);
521 int dpll_device_delete_ntf(struct dpll_device *dpll)
523 return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll);
527 __dpll_device_change_ntf(struct dpll_device *dpll)
529 return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll);
533 * dpll_device_change_ntf - notify that the dpll device has been changed
534 * @dpll: registered dpll pointer
536 * Context: acquires and holds a dpll_lock.
537 * Return: 0 if succeeds, error code otherwise.
539 int dpll_device_change_ntf(struct dpll_device *dpll)
543 mutex_lock(&dpll_lock);
544 ret = __dpll_device_change_ntf(dpll);
545 mutex_unlock(&dpll_lock);
549 EXPORT_SYMBOL_GPL(dpll_device_change_ntf);
552 dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)
558 if (WARN_ON(!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED)))
561 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
565 hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event);
568 ret = dpll_cmd_pin_get_one(msg, pin, NULL);
571 genlmsg_end(msg, hdr);
572 genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL);
577 genlmsg_cancel(msg, hdr);
584 int dpll_pin_create_ntf(struct dpll_pin *pin)
586 return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin);
589 int dpll_pin_delete_ntf(struct dpll_pin *pin)
591 return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
594 static int __dpll_pin_change_ntf(struct dpll_pin *pin)
596 return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
600 * dpll_pin_change_ntf - notify that the pin has been changed
601 * @pin: registered pin pointer
603 * Context: acquires and holds a dpll_lock.
604 * Return: 0 if succeeds, error code otherwise.
606 int dpll_pin_change_ntf(struct dpll_pin *pin)
610 mutex_lock(&dpll_lock);
611 ret = __dpll_pin_change_ntf(pin);
612 mutex_unlock(&dpll_lock);
616 EXPORT_SYMBOL_GPL(dpll_pin_change_ntf);
619 dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
620 struct netlink_ext_ack *extack)
622 u64 freq = nla_get_u64(a), old_freq;
623 struct dpll_pin_ref *ref, *failed;
624 const struct dpll_pin_ops *ops;
625 struct dpll_device *dpll;
629 if (!dpll_pin_is_freq_supported(pin, freq)) {
630 NL_SET_ERR_MSG_ATTR(extack, a, "frequency is not supported by the device");
634 xa_for_each(&pin->dpll_refs, i, ref) {
635 ops = dpll_pin_ops(ref);
636 if (!ops->frequency_set || !ops->frequency_get) {
637 NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
641 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
642 ops = dpll_pin_ops(ref);
644 ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
645 dpll_priv(dpll), &old_freq, extack);
647 NL_SET_ERR_MSG(extack, "unable to get old frequency value");
650 if (freq == old_freq)
653 xa_for_each(&pin->dpll_refs, i, ref) {
654 ops = dpll_pin_ops(ref);
656 ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
657 dpll, dpll_priv(dpll), freq, extack);
660 NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u",
665 __dpll_pin_change_ntf(pin);
670 xa_for_each(&pin->dpll_refs, i, ref) {
673 ops = dpll_pin_ops(ref);
675 if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
676 dpll, dpll_priv(dpll), old_freq, extack))
677 NL_SET_ERR_MSG(extack, "set frequency rollback failed");
683 dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
684 enum dpll_pin_state state,
685 struct netlink_ext_ack *extack)
687 struct dpll_pin_ref *parent_ref;
688 const struct dpll_pin_ops *ops;
689 struct dpll_pin_ref *dpll_ref;
690 void *pin_priv, *parent_priv;
691 struct dpll_pin *parent;
695 if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
696 pin->prop->capabilities)) {
697 NL_SET_ERR_MSG(extack, "state changing is not allowed");
700 parent = xa_load(&dpll_pin_xa, parent_idx);
703 parent_ref = xa_load(&pin->parent_refs, parent->pin_idx);
706 xa_for_each(&parent->dpll_refs, i, dpll_ref) {
707 ops = dpll_pin_ops(parent_ref);
708 if (!ops->state_on_pin_set)
710 pin_priv = dpll_pin_on_pin_priv(parent, pin);
711 parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, parent);
712 ret = ops->state_on_pin_set(pin, pin_priv, parent, parent_priv,
717 __dpll_pin_change_ntf(pin);
723 dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,
724 enum dpll_pin_state state,
725 struct netlink_ext_ack *extack)
727 const struct dpll_pin_ops *ops;
728 struct dpll_pin_ref *ref;
731 if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
732 pin->prop->capabilities)) {
733 NL_SET_ERR_MSG(extack, "state changing is not allowed");
736 ref = xa_load(&pin->dpll_refs, dpll->id);
737 ASSERT_NOT_NULL(ref);
738 ops = dpll_pin_ops(ref);
739 if (!ops->state_on_dpll_set)
741 ret = ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
742 dpll, dpll_priv(dpll), state, extack);
745 __dpll_pin_change_ntf(pin);
751 dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,
752 u32 prio, struct netlink_ext_ack *extack)
754 const struct dpll_pin_ops *ops;
755 struct dpll_pin_ref *ref;
758 if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE &
759 pin->prop->capabilities)) {
760 NL_SET_ERR_MSG(extack, "prio changing is not allowed");
763 ref = xa_load(&pin->dpll_refs, dpll->id);
764 ASSERT_NOT_NULL(ref);
765 ops = dpll_pin_ops(ref);
768 ret = ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
769 dpll_priv(dpll), prio, extack);
772 __dpll_pin_change_ntf(pin);
778 dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
779 enum dpll_pin_direction direction,
780 struct netlink_ext_ack *extack)
782 const struct dpll_pin_ops *ops;
783 struct dpll_pin_ref *ref;
786 if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE &
787 pin->prop->capabilities)) {
788 NL_SET_ERR_MSG(extack, "direction changing is not allowed");
791 ref = xa_load(&pin->dpll_refs, dpll->id);
792 ASSERT_NOT_NULL(ref);
793 ops = dpll_pin_ops(ref);
794 if (!ops->direction_set)
796 ret = ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
797 dpll, dpll_priv(dpll), direction, extack);
800 __dpll_pin_change_ntf(pin);
806 dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
807 struct netlink_ext_ack *extack)
809 struct dpll_pin_ref *ref, *failed;
810 const struct dpll_pin_ops *ops;
811 s32 phase_adj, old_phase_adj;
812 struct dpll_device *dpll;
816 phase_adj = nla_get_s32(phase_adj_attr);
817 if (phase_adj > pin->prop->phase_range.max ||
818 phase_adj < pin->prop->phase_range.min) {
819 NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
820 "phase adjust value not supported");
824 xa_for_each(&pin->dpll_refs, i, ref) {
825 ops = dpll_pin_ops(ref);
826 if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
827 NL_SET_ERR_MSG(extack, "phase adjust not supported");
831 ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
832 ops = dpll_pin_ops(ref);
834 ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
835 dpll, dpll_priv(dpll), &old_phase_adj,
838 NL_SET_ERR_MSG(extack, "unable to get old phase adjust value");
841 if (phase_adj == old_phase_adj)
844 xa_for_each(&pin->dpll_refs, i, ref) {
845 ops = dpll_pin_ops(ref);
847 ret = ops->phase_adjust_set(pin,
848 dpll_pin_on_dpll_priv(dpll, pin),
849 dpll, dpll_priv(dpll), phase_adj,
853 NL_SET_ERR_MSG_FMT(extack,
854 "phase adjust set failed for dpll_id:%u",
859 __dpll_pin_change_ntf(pin);
864 xa_for_each(&pin->dpll_refs, i, ref) {
867 ops = dpll_pin_ops(ref);
869 if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
870 dpll, dpll_priv(dpll), old_phase_adj,
872 NL_SET_ERR_MSG(extack, "set phase adjust rollback failed");
878 dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
879 struct netlink_ext_ack *extack)
881 struct nlattr *tb[DPLL_A_PIN_MAX + 1];
882 enum dpll_pin_direction direction;
883 enum dpll_pin_state state;
884 struct dpll_pin_ref *ref;
885 struct dpll_device *dpll;
889 nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
890 dpll_pin_parent_device_nl_policy, extack);
891 if (!tb[DPLL_A_PIN_PARENT_ID]) {
892 NL_SET_ERR_MSG(extack, "device parent id expected");
895 pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
896 dpll = xa_load(&dpll_device_xa, pdpll_idx);
898 NL_SET_ERR_MSG(extack, "parent device not found");
901 ref = xa_load(&pin->dpll_refs, dpll->id);
903 NL_SET_ERR_MSG(extack, "pin not connected to given parent device");
906 if (tb[DPLL_A_PIN_STATE]) {
907 state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
908 ret = dpll_pin_state_set(dpll, pin, state, extack);
912 if (tb[DPLL_A_PIN_PRIO]) {
913 prio = nla_get_u32(tb[DPLL_A_PIN_PRIO]);
914 ret = dpll_pin_prio_set(dpll, pin, prio, extack);
918 if (tb[DPLL_A_PIN_DIRECTION]) {
919 direction = nla_get_u32(tb[DPLL_A_PIN_DIRECTION]);
920 ret = dpll_pin_direction_set(pin, dpll, direction, extack);
928 dpll_pin_parent_pin_set(struct dpll_pin *pin, struct nlattr *parent_nest,
929 struct netlink_ext_ack *extack)
931 struct nlattr *tb[DPLL_A_PIN_MAX + 1];
935 nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
936 dpll_pin_parent_pin_nl_policy, extack);
937 if (!tb[DPLL_A_PIN_PARENT_ID]) {
938 NL_SET_ERR_MSG(extack, "device parent id expected");
941 ppin_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
943 if (tb[DPLL_A_PIN_STATE]) {
944 enum dpll_pin_state state = nla_get_u32(tb[DPLL_A_PIN_STATE]);
946 ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack);
955 dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
960 nla_for_each_attr(a, genlmsg_data(info->genlhdr),
961 genlmsg_len(info->genlhdr), rem) {
962 switch (nla_type(a)) {
963 case DPLL_A_PIN_FREQUENCY:
964 ret = dpll_pin_freq_set(pin, a, info->extack);
968 case DPLL_A_PIN_PHASE_ADJUST:
969 ret = dpll_pin_phase_adj_set(pin, a, info->extack);
973 case DPLL_A_PIN_PARENT_DEVICE:
974 ret = dpll_pin_parent_device_set(pin, a, info->extack);
978 case DPLL_A_PIN_PARENT_PIN:
979 ret = dpll_pin_parent_pin_set(pin, a, info->extack);
989 static struct dpll_pin *
990 dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
991 enum dpll_pin_type type, struct nlattr *board_label,
992 struct nlattr *panel_label, struct nlattr *package_label,
993 struct netlink_ext_ack *extack)
995 bool board_match, panel_match, package_match;
996 struct dpll_pin *pin_match = NULL, *pin;
997 const struct dpll_pin_properties *prop;
998 bool cid_match, mod_match, type_match;
1001 xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) {
1003 cid_match = clock_id ? pin->clock_id == clock_id : true;
1004 mod_match = mod_name_attr && module_name(pin->module) ?
1005 !nla_strcmp(mod_name_attr,
1006 module_name(pin->module)) : true;
1007 type_match = type ? prop->type == type : true;
1008 board_match = board_label ? (prop->board_label ?
1009 !nla_strcmp(board_label, prop->board_label) : false) :
1011 panel_match = panel_label ? (prop->panel_label ?
1012 !nla_strcmp(panel_label, prop->panel_label) : false) :
1014 package_match = package_label ? (prop->package_label ?
1015 !nla_strcmp(package_label, prop->package_label) :
1017 if (cid_match && mod_match && type_match && board_match &&
1018 panel_match && package_match) {
1020 NL_SET_ERR_MSG(extack, "multiple matches");
1021 return ERR_PTR(-EINVAL);
1027 NL_SET_ERR_MSG(extack, "not found");
1028 return ERR_PTR(-ENODEV);
1033 static struct dpll_pin *dpll_pin_find_from_nlattr(struct genl_info *info)
1035 struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL,
1036 *panel_label_attr = NULL, *package_label_attr = NULL;
1037 enum dpll_pin_type type = 0;
1041 nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1042 genlmsg_len(info->genlhdr), rem) {
1043 switch (nla_type(attr)) {
1044 case DPLL_A_PIN_CLOCK_ID:
1046 goto duplicated_attr;
1047 clock_id = nla_get_u64(attr);
1049 case DPLL_A_PIN_MODULE_NAME:
1051 goto duplicated_attr;
1052 mod_name_attr = attr;
1054 case DPLL_A_PIN_TYPE:
1056 goto duplicated_attr;
1057 type = nla_get_u32(attr);
1059 case DPLL_A_PIN_BOARD_LABEL:
1060 if (board_label_attr)
1061 goto duplicated_attr;
1062 board_label_attr = attr;
1064 case DPLL_A_PIN_PANEL_LABEL:
1065 if (panel_label_attr)
1066 goto duplicated_attr;
1067 panel_label_attr = attr;
1069 case DPLL_A_PIN_PACKAGE_LABEL:
1070 if (package_label_attr)
1071 goto duplicated_attr;
1072 package_label_attr = attr;
1078 if (!(clock_id || mod_name_attr || board_label_attr ||
1079 panel_label_attr || package_label_attr)) {
1080 NL_SET_ERR_MSG(info->extack, "missing attributes");
1081 return ERR_PTR(-EINVAL);
1083 return dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr,
1084 panel_label_attr, package_label_attr,
1087 NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1088 return ERR_PTR(-EINVAL);
1091 int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1093 struct dpll_pin *pin;
1094 struct sk_buff *msg;
1098 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1101 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1102 DPLL_CMD_PIN_ID_GET);
1107 pin = dpll_pin_find_from_nlattr(info);
1109 ret = dpll_msg_add_pin_handle(msg, pin);
1115 genlmsg_end(msg, hdr);
1117 return genlmsg_reply(msg, info);
1120 int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info)
1122 struct dpll_pin *pin = info->user_ptr[0];
1123 struct sk_buff *msg;
1129 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1132 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1138 ret = dpll_cmd_pin_get_one(msg, pin, info->extack);
1143 genlmsg_end(msg, hdr);
1145 return genlmsg_reply(msg, info);
1148 int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1150 struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1151 struct dpll_pin *pin;
1156 xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
1158 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1160 &dpll_nl_family, NLM_F_MULTI,
1166 ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
1168 genlmsg_cancel(skb, hdr);
1171 genlmsg_end(skb, hdr);
1173 if (ret == -EMSGSIZE) {
1180 int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info)
1182 struct dpll_pin *pin = info->user_ptr[0];
1184 return dpll_pin_set_from_nlattr(pin, info);
1187 static struct dpll_device *
1188 dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr,
1189 enum dpll_type type, struct netlink_ext_ack *extack)
1191 struct dpll_device *dpll_match = NULL, *dpll;
1192 bool cid_match, mod_match, type_match;
1195 xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) {
1196 cid_match = clock_id ? dpll->clock_id == clock_id : true;
1197 mod_match = mod_name_attr ? (module_name(dpll->module) ?
1198 !nla_strcmp(mod_name_attr,
1199 module_name(dpll->module)) : false) : true;
1200 type_match = type ? dpll->type == type : true;
1201 if (cid_match && mod_match && type_match) {
1203 NL_SET_ERR_MSG(extack, "multiple matches");
1204 return ERR_PTR(-EINVAL);
1210 NL_SET_ERR_MSG(extack, "not found");
1211 return ERR_PTR(-ENODEV);
1217 static struct dpll_device *
1218 dpll_device_find_from_nlattr(struct genl_info *info)
1220 struct nlattr *attr, *mod_name_attr = NULL;
1221 enum dpll_type type = 0;
1225 nla_for_each_attr(attr, genlmsg_data(info->genlhdr),
1226 genlmsg_len(info->genlhdr), rem) {
1227 switch (nla_type(attr)) {
1228 case DPLL_A_CLOCK_ID:
1230 goto duplicated_attr;
1231 clock_id = nla_get_u64(attr);
1233 case DPLL_A_MODULE_NAME:
1235 goto duplicated_attr;
1236 mod_name_attr = attr;
1240 goto duplicated_attr;
1241 type = nla_get_u32(attr);
1247 if (!clock_id && !mod_name_attr && !type) {
1248 NL_SET_ERR_MSG(info->extack, "missing attributes");
1249 return ERR_PTR(-EINVAL);
1251 return dpll_device_find(clock_id, mod_name_attr, type, info->extack);
1253 NL_SET_ERR_MSG(info->extack, "duplicated attribute");
1254 return ERR_PTR(-EINVAL);
1257 int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info)
1259 struct dpll_device *dpll;
1260 struct sk_buff *msg;
1264 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1267 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1268 DPLL_CMD_DEVICE_ID_GET);
1274 dpll = dpll_device_find_from_nlattr(info);
1275 if (!IS_ERR(dpll)) {
1276 ret = dpll_msg_add_dev_handle(msg, dpll);
1282 genlmsg_end(msg, hdr);
1284 return genlmsg_reply(msg, info);
1287 int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info)
1289 struct dpll_device *dpll = info->user_ptr[0];
1290 struct sk_buff *msg;
1294 msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1297 hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0,
1298 DPLL_CMD_DEVICE_GET);
1304 ret = dpll_device_get_one(dpll, msg, info->extack);
1309 genlmsg_end(msg, hdr);
1311 return genlmsg_reply(msg, info);
1314 int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info)
1316 /* placeholder for set command */
1320 int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
1322 struct dpll_dump_ctx *ctx = dpll_dump_context(cb);
1323 struct dpll_device *dpll;
1328 xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
1330 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1331 cb->nlh->nlmsg_seq, &dpll_nl_family,
1332 NLM_F_MULTI, DPLL_CMD_DEVICE_GET);
1337 ret = dpll_device_get_one(dpll, skb, cb->extack);
1339 genlmsg_cancel(skb, hdr);
1342 genlmsg_end(skb, hdr);
1344 if (ret == -EMSGSIZE) {
1351 int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1352 struct genl_info *info)
1356 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_ID))
1359 mutex_lock(&dpll_lock);
1360 id = nla_get_u32(info->attrs[DPLL_A_ID]);
1361 info->user_ptr[0] = dpll_device_get_by_id(id);
1362 if (!info->user_ptr[0]) {
1363 NL_SET_ERR_MSG(info->extack, "device not found");
1368 mutex_unlock(&dpll_lock);
1372 void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1373 struct genl_info *info)
1375 mutex_unlock(&dpll_lock);
1379 dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1380 struct genl_info *info)
1382 mutex_lock(&dpll_lock);
1388 dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1389 struct genl_info *info)
1391 mutex_unlock(&dpll_lock);
1394 int dpll_lock_dumpit(struct netlink_callback *cb)
1396 mutex_lock(&dpll_lock);
1401 int dpll_unlock_dumpit(struct netlink_callback *cb)
1403 mutex_unlock(&dpll_lock);
1408 int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1409 struct genl_info *info)
1413 mutex_lock(&dpll_lock);
1414 if (GENL_REQ_ATTR_CHECK(info, DPLL_A_PIN_ID)) {
1418 info->user_ptr[0] = xa_load(&dpll_pin_xa,
1419 nla_get_u32(info->attrs[DPLL_A_PIN_ID]));
1420 if (!info->user_ptr[0]) {
1421 NL_SET_ERR_MSG(info->extack, "pin not found");
1429 mutex_unlock(&dpll_lock);
1433 void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
1434 struct genl_info *info)
1436 mutex_unlock(&dpll_lock);