From ad3b9894995200ececc31fa585c46456c59769a7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 2 Feb 2023 00:24:47 +0100 Subject: [PATCH 01/93] dpll: spec: Add Netlink spec in YAML Add a protocol spec for DPLL. Add code generated from the spec. Signed-off-by: Jakub Kicinski Signed-off-by: Michal Michalik Signed-off-by: Arkadiusz Kubalewski Signed-off-by: Vadim Fedorenko --- Documentation/netlink/specs/dpll.yaml | 472 ++++++++++++++++++++++++++ drivers/dpll/dpll_nl.c | 126 +++++++ drivers/dpll/dpll_nl.h | 42 +++ include/uapi/linux/dpll.h | 202 +++++++++++ 4 files changed, 842 insertions(+) create mode 100644 Documentation/netlink/specs/dpll.yaml create mode 100644 drivers/dpll/dpll_nl.c create mode 100644 drivers/dpll/dpll_nl.h create mode 100644 include/uapi/linux/dpll.h diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml new file mode 100644 index 000000000000..67ca0f6cf2d5 --- /dev/null +++ b/Documentation/netlink/specs/dpll.yaml @@ -0,0 +1,472 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: dpll + +doc: DPLL subsystem. + +definitions: + - + type: enum + name: mode + doc: | + working-modes a dpll can support, differentiate if and how dpll selects + one of its sources to syntonize with it, valid values for DPLL_A_MODE + attribute + entries: + - + name: unspec + doc: unspecified value + - + name: manual + doc: source can be only selected by sending a request to dpll + - + name: automatic + doc: highest prio, valid source, auto selected by dpll + - + name: holdover + doc: dpll forced into holdover mode + - + name: freerun + doc: dpll driven on system clk, no holdover available + - + name: nco + doc: dpll driven by Numerically Controlled Oscillator + render-max: true + - + type: enum + name: lock-status + doc: | + provides information of dpll device lock status, valid values for + DPLL_A_LOCK_STATUS attribute + entries: + - + name: unspec + doc: unspecified value + - + name: unlocked + doc: | + dpll was not yet locked to any valid source (or is in one of + modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) + - + name: calibrating + doc: dpll is trying to lock to a valid signal + - + name: locked + doc: dpll is locked + - + name: holdover + doc: | + dpll is in holdover state - lost a valid lock or was forced by + selecting DPLL_MODE_HOLDOVER mode + render-max: true + - + type: const + name: temp-divider + value: 10 + doc: | + temperature divider allowing userspace to calculate the + temperature as float with single digit precision. + Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of + tempearture value. + Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of + temperature value. + - + type: enum + name: type + doc: type of dpll, valid values for DPLL_A_TYPE attribute + entries: + - + name: unspec + doc: unspecified value + - + name: pps + doc: dpll produces Pulse-Per-Second signal + - + name: eec + doc: dpll drives the Ethernet Equipment Clock + render-max: true + - + type: enum + name: pin-type + doc: | + defines possible types of a pin, valid values for DPLL_A_PIN_TYPE + attribute + entries: + - + name: unspec + doc: unspecified value + - + name: mux + doc: aggregates another layer of selectable pins + - + name: ext + doc: external source + - + name: synce-eth-port + doc: ethernet port PHY's recovered clock + - + name: int-oscillator + doc: device internal oscillator + - + name: gnss + doc: GNSS recovered clock + render-max: true + - + type: enum + name: pin-direction + doc: | + defines possible direction of a pin, valid values for + DPLL_A_PIN_DIRECTION attribute + entries: + - + name: unspec + doc: unspecified value + - + name: source + doc: pin used as a source of a signal + - + name: output + doc: pin used to output the signal + render-max: true + - + type: const + name: pin-frequency-1-hz + value: 1 + - + type: const + name: pin-frequency-10-mhz + value: 10000000 + - + type: enum + name: pin-state + doc: | + defines possible states of a pin, valid values for + DPLL_A_PIN_STATE attribute + entries: + - + name: unspec + doc: unspecified value + - + name: connected + doc: pin connected, active source of phase locked loop + - + name: disconnected + doc: pin disconnected, not considered as a valid source + - + name: selectable + doc: pin enabled for automatic source selection + render-max: true + - + type: flags + name: pin-caps + doc: | + defines possible capabilities of a pin, valid flags on + DPLL_A_PIN_CAPS attribute + entries: + - + name: direction-can-change + - + name: priority-can-change + - + name: state-can-change + - + type: enum + name: event + doc: events of dpll generic netlink family + entries: + - + name: unspec + doc: invalid event type + - + name: device-create + doc: dpll device created + - + name: device-delete + doc: dpll device deleted + - + name: device-change + doc: | + attribute of dpll device or pin changed, reason is to be found with + an attribute type (DPLL_A_*) received with the event + + +attribute-sets: + - + name: dpll + enum-name: dplla + attributes: + - + name: device + type: nest + value: 1 + multi-attr: true + nested-attributes: device + - + name: id + type: u32 + - + name: dev-name + type: string + - + name: bus-name + type: string + - + name: mode + type: u8 + enum: mode + - + name: mode-supported + type: u8 + enum: mode + multi-attr: true + - + name: lock-status + type: u8 + enum: lock-status + - + name: temp + type: s32 + - + name: clock-id + type: u64 + - + name: type + type: u8 + enum: type + - + name: pin-idx + type: u32 + - + name: pin-label + type: string + - + name: pin-type + type: u8 + enum: pin-type + - + name: pin-direction + type: u8 + enum: pin-direction + - + name: pin-frequency + type: u64 + - + name: pin-frequency-supported + type: nest + multi-attr: true + nested-attributes: pin-frequency-range + - + name: pin-frequency-min + type: u64 + - + name: pin-frequency-max + type: u64 + - + name: pin-prio + type: u32 + - + name: pin-state + type: u8 + enum: pin-state + - + name: pin-parent + type: nest + multi-attr: true + nested-attributes: pin-parent + - + name: pin-parent-idx + type: u32 + - + name: pin-rclk-device + type: string + - + name: pin-dpll-caps + type: u32 + - + name: device + subset-of: dpll + attributes: + - + name: id + type: u32 + value: 2 + - + name: dev-name + type: string + - + name: bus-name + type: string + - + name: mode + type: u8 + enum: mode + - + name: mode-supported + type: u8 + enum: mode + multi-attr: true + - + name: lock-status + type: u8 + enum: lock-status + - + name: temp + type: s32 + - + name: clock-id + type: u64 + - + name: type + type: u8 + enum: type + - + name: pin-prio + type: u32 + value: 19 + - + name: pin-state + type: u8 + enum: pin-state + - + name: pin-parent + subset-of: dpll + attributes: + - + name: pin-state + type: u8 + value: 20 + enum: pin-state + - + name: pin-parent-idx + type: u32 + value: 22 + - + name: pin-rclk-device + type: string + - + name: pin-frequency-range + subset-of: dpll + attributes: + - + name: pin-frequency-min + type: u64 + value: 17 + - + name: pin-frequency-max + type: u64 + +operations: + list: + - + name: unspec + doc: unused + + - + name: device-get + doc: | + Get list of DPLL devices (dump) or attributes of a single dpll device + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pre-doit + post: dpll-post-doit + request: + attributes: + - id + - bus-name + - dev-name + reply: + attributes: + - device + + dump: + pre: dpll-pre-dumpit + post: dpll-post-dumpit + reply: + attributes: + - device + + - + name: device-set + doc: Set attributes for a DPLL device + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pre-doit + post: dpll-post-doit + request: + attributes: + - id + - bus-name + - dev-name + - mode + + - + name: pin-get + doc: | + Get list of pins and its attributes. + - dump request without any attributes given - list all the pins in the system + - dump request with target dpll - list all the pins registered with a given dpll device + - do request with target dpll and target pin - single pin attributes + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pin-pre-doit + post: dpll-pin-post-doit + request: + attributes: + - id + - bus-name + - dev-name + - pin-idx + reply: &pin-attrs + attributes: + - pin-idx + - pin-label + - pin-type + - pin-direction + - pin-frequency + - pin-frequency-supported + - pin-parent + - pin-rclk-device + - pin-dpll-caps + - device + + dump: + pre: dpll-pin-pre-dumpit + post: dpll-pin-post-dumpit + request: + attributes: + - id + - bus-name + - dev-name + reply: *pin-attrs + + - + name: pin-set + doc: Set attributes of a target pin + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pin-pre-doit + post: dpll-pin-post-doit + request: + attributes: + - id + - bus-name + - dev-name + - pin-idx + - pin-frequency + - pin-direction + - pin-prio + - pin-state + - pin-parent-idx + +mcast-groups: + list: + - + name: monitor diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c new file mode 100644 index 000000000000..2f8643f401b0 --- /dev/null +++ b/drivers/dpll/dpll_nl.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "dpll_nl.h" + +#include + +/* DPLL_CMD_DEVICE_GET - do */ +static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_BUS_NAME + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DPLL_CMD_DEVICE_SET - do */ +static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_MODE + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_MODE] = NLA_POLICY_MAX(NLA_U8, 5), +}; + +/* DPLL_CMD_PIN_GET - do */ +static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_IDX + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_IDX] = { .type = NLA_U32, }, +}; + +/* DPLL_CMD_PIN_GET - dump */ +static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_BUS_NAME + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DPLL_CMD_PIN_SET - do */ +static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_IDX + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_IDX] = { .type = NLA_U32, }, + [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_MAX(NLA_U8, 2), + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, + [DPLL_A_PIN_STATE] = NLA_POLICY_MAX(NLA_U8, 3), + [DPLL_A_PIN_PARENT_IDX] = { .type = NLA_U32, }, +}; + +/* Ops table for dpll */ +static const struct genl_split_ops dpll_nl_ops[] = { + { + .cmd = DPLL_CMD_DEVICE_GET, + .pre_doit = dpll_pre_doit, + .doit = dpll_nl_device_get_doit, + .post_doit = dpll_post_doit, + .policy = dpll_device_get_nl_policy, + .maxattr = DPLL_A_BUS_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_DEVICE_GET, + .start = dpll_pre_dumpit, + .dumpit = dpll_nl_device_get_dumpit, + .done = dpll_post_dumpit, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DPLL_CMD_DEVICE_SET, + .pre_doit = dpll_pre_doit, + .doit = dpll_nl_device_set_doit, + .post_doit = dpll_post_doit, + .policy = dpll_device_set_nl_policy, + .maxattr = DPLL_A_MODE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_PIN_GET, + .pre_doit = dpll_pin_pre_doit, + .doit = dpll_nl_pin_get_doit, + .post_doit = dpll_pin_post_doit, + .policy = dpll_pin_get_do_nl_policy, + .maxattr = DPLL_A_PIN_IDX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_PIN_GET, + .start = dpll_pin_pre_dumpit, + .dumpit = dpll_nl_pin_get_dumpit, + .done = dpll_pin_post_dumpit, + .policy = dpll_pin_get_dump_nl_policy, + .maxattr = DPLL_A_BUS_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DPLL_CMD_PIN_SET, + .pre_doit = dpll_pin_pre_doit, + .doit = dpll_nl_pin_set_doit, + .post_doit = dpll_pin_post_doit, + .policy = dpll_pin_set_nl_policy, + .maxattr = DPLL_A_PIN_PARENT_IDX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, +}; + +static const struct genl_multicast_group dpll_nl_mcgrps[] = { + [DPLL_NLGRP_MONITOR] = { "monitor", }, +}; + +struct genl_family dpll_nl_family __ro_after_init = { + .name = DPLL_FAMILY_NAME, + .version = DPLL_FAMILY_VERSION, + .netnsok = true, + .parallel_ops = true, + .module = THIS_MODULE, + .split_ops = dpll_nl_ops, + .n_split_ops = ARRAY_SIZE(dpll_nl_ops), + .mcgrps = dpll_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(dpll_nl_mcgrps), +}; diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h new file mode 100644 index 000000000000..57ab2da562ba --- /dev/null +++ b/drivers/dpll/dpll_nl.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_DPLL_GEN_H +#define _LINUX_DPLL_GEN_H + +#include +#include + +#include + +int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int dpll_pre_dumpit(struct netlink_callback *cb); +int dpll_pin_pre_dumpit(struct netlink_callback *cb); +int dpll_post_dumpit(struct netlink_callback *cb); +int dpll_pin_post_dumpit(struct netlink_callback *cb); + +int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info); + +enum { + DPLL_NLGRP_MONITOR, +}; + +extern struct genl_family dpll_nl_family; + +#endif /* _LINUX_DPLL_GEN_H */ diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h new file mode 100644 index 000000000000..e188bc189754 --- /dev/null +++ b/include/uapi/linux/dpll.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN uapi header */ + +#ifndef _UAPI_LINUX_DPLL_H +#define _UAPI_LINUX_DPLL_H + +#define DPLL_FAMILY_NAME "dpll" +#define DPLL_FAMILY_VERSION 1 + +/** + * enum dpll_mode - working-modes a dpll can support, differentiate if and how + * dpll selects one of its sources to syntonize with it, valid values for + * DPLL_A_MODE attribute + * @DPLL_MODE_UNSPEC: unspecified value + * @DPLL_MODE_MANUAL: source can be only selected by sending a request to dpll + * @DPLL_MODE_AUTOMATIC: highest prio, valid source, auto selected by dpll + * @DPLL_MODE_HOLDOVER: dpll forced into holdover mode + * @DPLL_MODE_FREERUN: dpll driven on system clk, no holdover available + * @DPLL_MODE_NCO: dpll driven by Numerically Controlled Oscillator + */ +enum dpll_mode { + DPLL_MODE_UNSPEC, + DPLL_MODE_MANUAL, + DPLL_MODE_AUTOMATIC, + DPLL_MODE_HOLDOVER, + DPLL_MODE_FREERUN, + DPLL_MODE_NCO, + + __DPLL_MODE_MAX, + DPLL_MODE_MAX = (__DPLL_MODE_MAX - 1) +}; + +/** + * enum dpll_lock_status - provides information of dpll device lock status, + * valid values for DPLL_A_LOCK_STATUS attribute + * @DPLL_LOCK_STATUS_UNSPEC: unspecified value + * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid source (or + * is in one of modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) + * @DPLL_LOCK_STATUS_CALIBRATING: dpll is trying to lock to a valid signal + * @DPLL_LOCK_STATUS_LOCKED: dpll is locked + * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or + * was forced by selecting DPLL_MODE_HOLDOVER mode + */ +enum dpll_lock_status { + DPLL_LOCK_STATUS_UNSPEC, + DPLL_LOCK_STATUS_UNLOCKED, + DPLL_LOCK_STATUS_CALIBRATING, + DPLL_LOCK_STATUS_LOCKED, + DPLL_LOCK_STATUS_HOLDOVER, + + __DPLL_LOCK_STATUS_MAX, + DPLL_LOCK_STATUS_MAX = (__DPLL_LOCK_STATUS_MAX - 1) +}; + +#define DPLL_TEMP_DIVIDER 10 + +/** + * enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute + * @DPLL_TYPE_UNSPEC: unspecified value + * @DPLL_TYPE_PPS: dpll produces Pulse-Per-Second signal + * @DPLL_TYPE_EEC: dpll drives the Ethernet Equipment Clock + */ +enum dpll_type { + DPLL_TYPE_UNSPEC, + DPLL_TYPE_PPS, + DPLL_TYPE_EEC, + + __DPLL_TYPE_MAX, + DPLL_TYPE_MAX = (__DPLL_TYPE_MAX - 1) +}; + +/** + * enum dpll_pin_type - defines possible types of a pin, valid values for + * DPLL_A_PIN_TYPE attribute + * @DPLL_PIN_TYPE_UNSPEC: unspecified value + * @DPLL_PIN_TYPE_MUX: aggregates another layer of selectable pins + * @DPLL_PIN_TYPE_EXT: external source + * @DPLL_PIN_TYPE_SYNCE_ETH_PORT: ethernet port PHY's recovered clock + * @DPLL_PIN_TYPE_INT_OSCILLATOR: device internal oscillator + * @DPLL_PIN_TYPE_GNSS: GNSS recovered clock + */ +enum dpll_pin_type { + DPLL_PIN_TYPE_UNSPEC, + DPLL_PIN_TYPE_MUX, + DPLL_PIN_TYPE_EXT, + DPLL_PIN_TYPE_SYNCE_ETH_PORT, + DPLL_PIN_TYPE_INT_OSCILLATOR, + DPLL_PIN_TYPE_GNSS, + + __DPLL_PIN_TYPE_MAX, + DPLL_PIN_TYPE_MAX = (__DPLL_PIN_TYPE_MAX - 1) +}; + +/** + * enum dpll_pin_direction - defines possible direction of a pin, valid values + * for DPLL_A_PIN_DIRECTION attribute + * @DPLL_PIN_DIRECTION_UNSPEC: unspecified value + * @DPLL_PIN_DIRECTION_SOURCE: pin used as a source of a signal + * @DPLL_PIN_DIRECTION_OUTPUT: pin used to output the signal + */ +enum dpll_pin_direction { + DPLL_PIN_DIRECTION_UNSPEC, + DPLL_PIN_DIRECTION_SOURCE, + DPLL_PIN_DIRECTION_OUTPUT, + + __DPLL_PIN_DIRECTION_MAX, + DPLL_PIN_DIRECTION_MAX = (__DPLL_PIN_DIRECTION_MAX - 1) +}; + +#define DPLL_PIN_FREQUENCY_1_HZ 1 +#define DPLL_PIN_FREQUENCY_10_MHZ 10000000 + +/** + * enum dpll_pin_state - defines possible states of a pin, valid values for + * DPLL_A_PIN_STATE attribute + * @DPLL_PIN_STATE_UNSPEC: unspecified value + * @DPLL_PIN_STATE_CONNECTED: pin connected, active source of phase locked loop + * @DPLL_PIN_STATE_DISCONNECTED: pin disconnected, not considered as a valid + * source + * @DPLL_PIN_STATE_SELECTABLE: pin enabled for automatic source selection + */ +enum dpll_pin_state { + DPLL_PIN_STATE_UNSPEC, + DPLL_PIN_STATE_CONNECTED, + DPLL_PIN_STATE_DISCONNECTED, + DPLL_PIN_STATE_SELECTABLE, + + __DPLL_PIN_STATE_MAX, + DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1) +}; + +/** + * enum dpll_pin_caps - defines possible capabilities of a pin, valid flags on + * DPLL_A_PIN_CAPS attribute + */ +enum dpll_pin_caps { + DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE = 1, + DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE = 2, + DPLL_PIN_CAPS_STATE_CAN_CHANGE = 4, +}; + +/** + * enum dpll_event - events of dpll generic netlink family + * @DPLL_EVENT_UNSPEC: invalid event type + * @DPLL_EVENT_DEVICE_CREATE: dpll device created + * @DPLL_EVENT_DEVICE_DELETE: dpll device deleted + * @DPLL_EVENT_DEVICE_CHANGE: attribute of dpll device or pin changed, reason + * is to be found with an attribute type (DPLL_A_*) received with the event + */ +enum dpll_event { + DPLL_EVENT_UNSPEC, + DPLL_EVENT_DEVICE_CREATE, + DPLL_EVENT_DEVICE_DELETE, + DPLL_EVENT_DEVICE_CHANGE, +}; + +enum dplla { + DPLL_A_DEVICE = 1, + DPLL_A_ID, + DPLL_A_DEV_NAME, + DPLL_A_BUS_NAME, + DPLL_A_MODE, + DPLL_A_MODE_SUPPORTED, + DPLL_A_LOCK_STATUS, + DPLL_A_TEMP, + DPLL_A_CLOCK_ID, + DPLL_A_TYPE, + DPLL_A_PIN_IDX, + DPLL_A_PIN_LABEL, + DPLL_A_PIN_TYPE, + DPLL_A_PIN_DIRECTION, + DPLL_A_PIN_FREQUENCY, + DPLL_A_PIN_FREQUENCY_SUPPORTED, + DPLL_A_PIN_FREQUENCY_MIN, + DPLL_A_PIN_FREQUENCY_MAX, + DPLL_A_PIN_PRIO, + DPLL_A_PIN_STATE, + DPLL_A_PIN_PARENT, + DPLL_A_PIN_PARENT_IDX, + DPLL_A_PIN_RCLK_DEVICE, + DPLL_A_PIN_DPLL_CAPS, + + __DPLL_A_MAX, + DPLL_A_MAX = (__DPLL_A_MAX - 1) +}; + +enum { + DPLL_CMD_UNSPEC = 1, + DPLL_CMD_DEVICE_GET, + DPLL_CMD_DEVICE_SET, + DPLL_CMD_PIN_GET, + DPLL_CMD_PIN_SET, + + __DPLL_CMD_MAX, + DPLL_CMD_MAX = (__DPLL_CMD_MAX - 1) +}; + +#define DPLL_MCGRP_MONITOR "monitor" + +#endif /* _UAPI_LINUX_DPLL_H */ From 5609d172f804f3e6c4bf014b7a67593d74fddff4 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Sat, 11 Mar 2023 17:53:56 -0800 Subject: [PATCH 02/93] dpll: Add DPLL framework base functions DPLL framework is used to represent and configure DPLL devices in systems. Each device that has DPLL and can configure sources and outputs can use this framework. Netlink interface is used to provide configuration data and to receive notification messages about changes in the configuration or status of DPLL device. Inputs and outputs of the DPLL device are represented as special objects which could be dynamically added to and removed from DPLL device. Co-developed-by: Milena Olech Signed-off-by: Milena Olech Co-developed-by: Michal Michalik Signed-off-by: Michal Michalik Co-developed-by: Arkadiusz Kubalewski Signed-off-by: Arkadiusz Kubalewski Signed-off-by: Vadim Fedorenko --- MAINTAINERS | 8 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/dpll/Kconfig | 7 + drivers/dpll/Makefile | 10 + drivers/dpll/dpll_core.c | 939 ++++++++++++++++++++++++++++++++++ drivers/dpll/dpll_core.h | 113 +++++ drivers/dpll/dpll_netlink.c | 972 ++++++++++++++++++++++++++++++++++++ drivers/dpll/dpll_netlink.h | 27 + include/linux/dpll.h | 274 ++++++++++ include/uapi/linux/dpll.h | 2 + 11 files changed, 2355 insertions(+) create mode 100644 drivers/dpll/Kconfig create mode 100644 drivers/dpll/Makefile create mode 100644 drivers/dpll/dpll_core.c create mode 100644 drivers/dpll/dpll_core.h create mode 100644 drivers/dpll/dpll_netlink.c create mode 100644 drivers/dpll/dpll_netlink.h create mode 100644 include/linux/dpll.h diff --git a/MAINTAINERS b/MAINTAINERS index 288d9a5edb9d..0e69429ecc55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6306,6 +6306,14 @@ F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/switch-drive F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch* F: drivers/net/ethernet/freescale/dpaa2/dpsw* +DPLL CLOCK SUBSYSTEM +M: Vadim Fedorenko +L: netdev@vger.kernel.org +S: Maintained +F: drivers/dpll/* +F: include/net/dpll.h +F: include/uapi/linux/dpll.h + DRBD DRIVER M: Philipp Reisner M: Lars Ellenberg diff --git a/drivers/Kconfig b/drivers/Kconfig index 514ae6b24cb2..ce5f63918eba 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -243,4 +243,6 @@ source "drivers/hte/Kconfig" source "drivers/cdx/Kconfig" +source "drivers/dpll/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 7241d80a7b29..6fea42a6dd05 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -195,3 +195,4 @@ obj-$(CONFIG_PECI) += peci/ obj-$(CONFIG_HTE) += hte/ obj-$(CONFIG_DRM_ACCEL) += accel/ obj-$(CONFIG_CDX_BUS) += cdx/ +obj-$(CONFIG_DPLL) += dpll/ diff --git a/drivers/dpll/Kconfig b/drivers/dpll/Kconfig new file mode 100644 index 000000000000..a4cae73f20d3 --- /dev/null +++ b/drivers/dpll/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Generic DPLL drivers configuration +# + +config DPLL + bool diff --git a/drivers/dpll/Makefile b/drivers/dpll/Makefile new file mode 100644 index 000000000000..803bb5db7793 --- /dev/null +++ b/drivers/dpll/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for DPLL drivers. +# + +obj-$(CONFIG_DPLL) += dpll.o +dpll-y += dpll_core.o +dpll-y += dpll_netlink.o +dpll-y += dpll_nl.o + diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c new file mode 100644 index 000000000000..8a2370740026 --- /dev/null +++ b/drivers/dpll/dpll_core.c @@ -0,0 +1,939 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dpll_core.c - Generic DPLL Management class support. + * + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Intel Corporation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "dpll_core.h" + +DEFINE_MUTEX(dpll_xa_lock); + +DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); +DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); + +#define ASSERT_DPLL_REGISTERED(d) \ + WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) +#define ASSERT_DPLL_NOT_REGISTERED(d) \ + WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) + +/** + * dpll_device_get_by_id - find dpll device by it's id + * @id: id of searched dpll + * + * Return: + * * dpll_device struct if found + * * NULL otherwise + */ +struct dpll_device *dpll_device_get_by_id(int id) +{ + if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) + return xa_load(&dpll_device_xa, id); + + return NULL; +} + +/** + * dpll_device_get_by_name - find dpll device by it's id + * @bus_name: bus name of searched dpll + * @dev_name: dev name of searched dpll + * + * Return: + * * dpll_device struct if found + * * NULL otherwise + */ +struct dpll_device * +dpll_device_get_by_name(const char *bus_name, const char *device_name) +{ + struct dpll_device *dpll, *ret = NULL; + unsigned long i; + + xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { + if (!strcmp(dev_bus_name(&dpll->dev), bus_name) && + !strcmp(dev_name(&dpll->dev), device_name)) { + ret = dpll; + break; + } + } + + return ret; +} + +static struct dpll_pin_registration * +dpll_pin_registration_find(struct dpll_pin_ref *ref, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_registration *reg; + + list_for_each_entry(reg, &ref->registration_list, list) { + if (reg->ops == ops && reg->priv == priv) + return reg; + } + return NULL; +} + +/** + * dpll_xa_ref_pin_add - add pin reference to a given xarray + * @xa_pins: dpll_pin_ref xarray holding pins + * @pin: pin being added + * @ops: ops for a pin + * @priv: pointer to private data of owner + * + * Allocate and create reference of a pin and enlist a registration + * structure storing ops and priv pointers of a caller registant. + * + * Return: + * * 0 on success + * * -ENOMEM on failed allocation + */ +static int +dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + bool ref_exists = false; + unsigned long i; + int ret; + + xa_for_each(xa_pins, i, ref) { + if (ref->pin != pin) + continue; + reg = dpll_pin_registration_find(ref, ops, priv); + if (reg) { + refcount_inc(&ref->refcount); + return 0; + } + ref_exists = true; + break; + } + + if (!ref_exists) { + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return -ENOMEM; + ref->pin = pin; + INIT_LIST_HEAD(&ref->registration_list); + ret = xa_insert(xa_pins, pin->pin_idx, ref, GFP_KERNEL); + if (ret) { + kfree(ref); + return ret; + } + refcount_set(&ref->refcount, 1); + } + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) { + if (!ref_exists) + kfree(ref); + return -ENOMEM; + } + reg->ops = ops; + reg->priv = priv; + if (ref_exists) + refcount_inc(&ref->refcount); + list_add_tail(®->list, &ref->registration_list); + + return 0; +} + +/** + * dpll_xa_ref_pin_del - remove reference of a pin from xarray + * @xa_pins: dpll_pin_ref xarray holding pins + * @pin: pointer to a pin + * + * Decrement refcount of existing pin reference on given xarray. + * If all registrations are lifted delete the reference and free its memory. + * + * Return: + * * 0 on success + * * -EINVAL if reference to a pin was not found + */ +static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + unsigned long i; + + xa_for_each(xa_pins, i, ref) { + if (ref->pin != pin) + continue; + reg = dpll_pin_registration_find(ref, ops, priv); + if (WARN_ON(!reg)) + return -EINVAL; + if (refcount_dec_and_test(&ref->refcount)) { + list_del(®->list); + kfree(reg); + xa_erase(xa_pins, i); + WARN_ON(!list_empty(&ref->registration_list)); + kfree(ref); + } + return 0; + } + + return -EINVAL; +} + +/** + * dpll_xa_ref_dpll_add - add dpll reference to a given xarray + * @xa_dplls: dpll_pin_ref xarray holding dplls + * @dpll: dpll being added + * @ops: pin-reference ops for a dpll + * @priv: pointer to private data of owner + * + * Allocate and create reference of a dpll-pin ops or increase refcount + * on existing dpll reference on given xarray. + * + * Return: + * * 0 on success + * * -ENOMEM on failed allocation + */ +static int +dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + bool ref_exists = false; + unsigned long i; + int ret; + + xa_for_each(xa_dplls, i, ref) { + if (ref->dpll != dpll) + continue; + reg = dpll_pin_registration_find(ref, ops, priv); + if (reg) { + refcount_inc(&ref->refcount); + return 0; + } + ref_exists = true; + break; + } + + if (!ref_exists) { + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return -ENOMEM; + ref->dpll = dpll; + INIT_LIST_HEAD(&ref->registration_list); + ret = xa_insert(xa_dplls, dpll->device_idx, ref, GFP_KERNEL); + if (ret) { + kfree(ref); + return ret; + } + refcount_set(&ref->refcount, 1); + } + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) { + if (!ref_exists) + kfree(ref); + return -ENOMEM; + } + reg->ops = ops; + reg->priv = priv; + if (ref_exists) + refcount_inc(&ref->refcount); + list_add_tail(®->list, &ref->registration_list); + + return 0; +} + +/** + * dpll_xa_ref_dpll_del - remove reference of a dpll from xarray + * @xa_dplls: dpll_pin_ref xarray holding dplls + * @dpll: pointer to a dpll to remove + * + * Decrement refcount of existing dpll reference on given xarray. + * If all references are dropped, delete the reference and free its memory. + */ +static void +dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + unsigned long i; + + xa_for_each(xa_dplls, i, ref) { + if (ref->dpll != dpll) + continue; + reg = dpll_pin_registration_find(ref, ops, priv); + if (WARN_ON(!reg)) + return; + if (refcount_dec_and_test(&ref->refcount)) { + list_del(®->list); + kfree(reg); + xa_erase(xa_dplls, i); + WARN_ON(!list_empty(&ref->registration_list)); + kfree(ref); + } + return; + } +} + +/** + * dpll_xa_ref_dpll_find - find dpll reference on xarray + * @xa_dplls: dpll_pin_ref xarray holding dplls + * @dpll: pointer to a dpll + * + * Search for dpll-pin ops reference struct of a given dpll on given xarray. + * + * Return: + * * pin reference struct pointer on success + * * NULL - reference to a pin was not found + */ +struct dpll_pin_ref * +dpll_xa_ref_dpll_find(struct xarray *xa_refs, const struct dpll_device *dpll) +{ + struct dpll_pin_ref *ref; + unsigned long i; + + xa_for_each(xa_refs, i, ref) { + if (ref->dpll == dpll) + return ref; + } + + return NULL; +} + +struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs) +{ + struct dpll_pin_ref *ref; + unsigned long i = 0; + + ref = xa_find(xa_refs, &i, ULONG_MAX, XA_PRESENT); + WARN_ON(!ref); + return ref; +} + +/** + * dpll_device_alloc - allocate the memory for dpll device + * @clock_id: clock_id of creator + * @device_idx: id given by dev driver + * @module: reference to registering module + * + * Allocates memory and initialize dpll device, hold its reference on global + * xarray. + * + * Return: + * * dpll_device struct pointer if succeeded + * * ERR_PTR(X) - failed allocation + */ +static struct dpll_device * +dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) +{ + struct dpll_device *dpll; + int ret; + + dpll = kzalloc(sizeof(*dpll), GFP_KERNEL); + if (!dpll) + return ERR_PTR(-ENOMEM); + refcount_set(&dpll->refcount, 1); + INIT_LIST_HEAD(&dpll->registration_list); + dpll->device_idx = device_idx; + dpll->clock_id = clock_id; + dpll->module = module; + ret = xa_alloc(&dpll_device_xa, &dpll->id, dpll, xa_limit_16b, + GFP_KERNEL); + if (ret) { + kfree(dpll); + return ERR_PTR(ret); + } + xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC); + + return dpll; +} + +/** + * dpll_device_get - find existing or create new dpll device + * @clock_id: clock_id of creator + * @device_idx: idx given by device driver + * @module: reference to registering module + * + * Get existing object of a dpll device, unique for given arguments. + * Create new if doesn't exist yet. + * + * Return: + * * valid dpll_device struct pointer if succeeded + * * ERR_PTR of an error + */ +struct dpll_device * +dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) +{ + struct dpll_device *dpll, *ret = NULL; + unsigned long index; + + mutex_lock(&dpll_xa_lock); + xa_for_each(&dpll_device_xa, index, dpll) { + if (dpll->clock_id == clock_id && + dpll->device_idx == device_idx && + dpll->module == module) { + ret = dpll; + refcount_inc(&ret->refcount); + break; + } + } + if (!ret) + ret = dpll_device_alloc(clock_id, device_idx, module); + mutex_unlock(&dpll_xa_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_device_get); + +/** + * dpll_device_put - decrease the refcount and free memory if possible + * @dpll: dpll_device struct pointer + * + * Drop reference for a dpll device, if all references are gone, delete + * dpll device object. + */ +void dpll_device_put(struct dpll_device *dpll) +{ + if (!dpll) + return; + mutex_lock(&dpll_xa_lock); + if (refcount_dec_and_test(&dpll->refcount)) { + ASSERT_DPLL_NOT_REGISTERED(dpll); + WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); + xa_destroy(&dpll->pin_refs); + xa_erase(&dpll_device_xa, dpll->id); + WARN_ON(!list_empty(&dpll->registration_list)); + kfree(dpll); + } + mutex_unlock(&dpll_xa_lock); +} +EXPORT_SYMBOL_GPL(dpll_device_put); + +static struct dpll_device_registration * +dpll_device_registration_find(struct dpll_device *dpll, + const struct dpll_device_ops *ops, void *priv) +{ + struct dpll_device_registration *reg; + + list_for_each_entry(reg, &dpll->registration_list, list) { + if (reg->ops == ops && reg->priv == priv) + return reg; + } + return NULL; +} + +/** + * dpll_device_register - register the dpll device in the subsystem + * @dpll: pointer to a dpll + * @type: type of a dpll + * @ops: ops for a dpll device + * @priv: pointer to private information of owner + * @owner: pointer to owner device + * + * Make dpll device available for user space. + * + * Return: + * * 0 on success + * * -EINVAL on failure + */ +int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, + const struct dpll_device_ops *ops, void *priv, + struct device *owner) +{ + struct dpll_device_registration *reg; + bool first_registration = false; + + if (WARN_ON(!ops || !owner)) + return -EINVAL; + if (WARN_ON(type <= DPLL_TYPE_UNSPEC || type > DPLL_TYPE_MAX)) + return -EINVAL; + + mutex_lock(&dpll_xa_lock); + reg = dpll_device_registration_find(dpll, ops, priv); + if (reg) { + mutex_unlock(&dpll_xa_lock); + return -EEXIST; + } + + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) { + mutex_unlock(&dpll_xa_lock); + return -EEXIST; + } + reg->ops = ops; + reg->priv = priv; + + dpll->dev.bus = owner->bus; + dpll->parent = owner; + dpll->type = type; + dev_set_name(&dpll->dev, "%s/%llx/%d", module_name(dpll->module), + dpll->clock_id, dpll->device_idx); + + first_registration = list_empty(&dpll->registration_list); + list_add_tail(®->list, &dpll->registration_list); + if (!first_registration) { + mutex_unlock(&dpll_xa_lock); + return 0; + } + + xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); + mutex_unlock(&dpll_xa_lock); + dpll_notify_device_create(dpll); + + return 0; +} +EXPORT_SYMBOL_GPL(dpll_device_register); + +/** + * dpll_device_unregister - deregister dpll device + * @dpll: registered dpll pointer + * @ops: ops for a dpll device + * @priv: pointer to private information of owner + * + * Deregister device, make it unavailable for userspace. + * Note: It does not free the memory + */ +void dpll_device_unregister(struct dpll_device *dpll, + const struct dpll_device_ops *ops, void *priv) +{ + struct dpll_device_registration *reg; + + mutex_lock(&dpll_xa_lock); + ASSERT_DPLL_REGISTERED(dpll); + + reg = dpll_device_registration_find(dpll, ops, priv); + if (WARN_ON(!reg)) { + mutex_unlock(&dpll_xa_lock); + return; + } + list_del(®->list); + kfree(reg); + + if (!list_empty(&dpll->registration_list)) { + mutex_unlock(&dpll_xa_lock); + return; + } + xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); + mutex_unlock(&dpll_xa_lock); + dpll_notify_device_delete(dpll); +} +EXPORT_SYMBOL_GPL(dpll_device_unregister); + +/** + * dpll_pin_alloc - allocate the memory for dpll pin + * @clock_id: clock_id of creator + * @pin_idx: idx given by dev driver + * @module: reference to registering module + * @prop: dpll pin properties + * + * Return: + * valid allocated dpll_pin struct pointer if succeeded + * ERR_PTR of an error + */ +static struct dpll_pin * +dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, + const struct dpll_pin_properties *prop) +{ + struct dpll_pin *pin; + int ret, fs_size; + + pin = kzalloc(sizeof(*pin), GFP_KERNEL); + if (!pin) + return ERR_PTR(-ENOMEM); + pin->pin_idx = pin_idx; + pin->clock_id = clock_id; + pin->module = module; + refcount_set(&pin->refcount, 1); + if (WARN_ON(!prop->label)) { + ret = -EINVAL; + goto err; + } + pin->prop.label = kstrdup(prop->label, GFP_KERNEL); + if (!pin->prop.label) { + ret = -ENOMEM; + goto err; + } + if (WARN_ON(prop->type <= DPLL_PIN_TYPE_UNSPEC || + prop->type > DPLL_PIN_TYPE_MAX)) { + ret = -EINVAL; + goto err; + } + pin->prop.type = prop->type; + pin->prop.capabilities = prop->capabilities; + if (prop->freq_supported_num) { + fs_size = sizeof(*pin->prop.freq_supported) * + prop->freq_supported_num; + pin->prop.freq_supported = kzalloc(fs_size, GFP_KERNEL); + if (!pin->prop.freq_supported) { + ret = -ENOMEM; + goto err; + } + memcpy(pin->prop.freq_supported, prop->freq_supported, fs_size); + pin->prop.freq_supported_num = prop->freq_supported_num; + } + xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); + xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); + ret = xa_alloc(&dpll_pin_xa, &pin->id, pin, xa_limit_16b, GFP_KERNEL); + if (ret) + goto err; + return pin; +err: + xa_destroy(&pin->dpll_refs); + xa_destroy(&pin->parent_refs); + kfree(pin->prop.label); + kfree(pin->rclk_dev_name); + kfree(pin); + return ERR_PTR(ret); +} + +/** + * dpll_pin_get - find existing or create new dpll pin + * @clock_id: clock_id of creator + * @pin_idx: idx given by dev driver + * @module: reference to registering module + * @prop: dpll pin properties + * + * Get existing object of a pin (unique for given arguments) or create new + * if doesn't exist yet. + * + * Return: + * * valid allocated dpll_pin struct pointer if succeeded + * * ERR_PTR of an error + */ +struct dpll_pin * +dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module, + const struct dpll_pin_properties *prop) +{ + struct dpll_pin *pos, *ret = NULL; + unsigned long i; + + xa_for_each(&dpll_pin_xa, i, pos) { + if (pos->clock_id == clock_id && + pos->pin_idx == pin_idx && + pos->module == module) { + ret = pos; + refcount_inc(&ret->refcount); + break; + } + } + if (!ret) + ret = dpll_pin_alloc(clock_id, pin_idx, module, prop); + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_pin_get); + +/** + * dpll_pin_put - decrease the refcount and free memory if possible + * @dpll: dpll_device struct pointer + * + * Drop reference for a pin, if all references are gone, delete pin object. + */ +void dpll_pin_put(struct dpll_pin *pin) +{ + if (!pin) + return; + if (refcount_dec_and_test(&pin->refcount)) { + xa_destroy(&pin->dpll_refs); + xa_destroy(&pin->parent_refs); + xa_erase(&dpll_pin_xa, pin->id); + kfree(pin->prop.label); + kfree(pin->prop.freq_supported); + kfree(pin->rclk_dev_name); + kfree(pin); + } +} +EXPORT_SYMBOL_GPL(dpll_pin_put); + +static int +__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, + const char *rclk_device_name) +{ + int ret; + + if (WARN_ON(!ops)) + return -EINVAL; + + if (rclk_device_name && !pin->rclk_dev_name) { + pin->rclk_dev_name = kstrdup(rclk_device_name, GFP_KERNEL); + if (!pin->rclk_dev_name) + return -ENOMEM; + } + ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv); + if (ret) + goto rclk_free; + ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv); + if (ret) + goto ref_pin_del; + else + dpll_pin_notify(dpll, pin, DPLL_A_PIN_IDX); + + return ret; + +ref_pin_del: + dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); +rclk_free: + kfree(pin->rclk_dev_name); + return ret; +} + +/** + * dpll_pin_register - register the dpll pin in the subsystem + * @dpll: pointer to a dpll + * @pin: pointer to a dpll pin + * @ops: ops for a dpll pin ops + * @priv: pointer to private information of owner + * @rclk_device: pointer to recovered clock device + * + * Return: + * * 0 on success + * * -EINVAL - missing dpll or pin + * * -ENOMEM - failed to allocate memory + */ +int +dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, + struct device *rclk_device) +{ + const char *rclk_name = rclk_device ? dev_name(rclk_device) : NULL; + int ret; + + mutex_lock(&dpll_xa_lock); + ret = __dpll_pin_register(dpll, pin, ops, priv, rclk_name); + mutex_unlock(&dpll_xa_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_pin_register); + +static void +__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv) +{ + dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); + dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv); +} + +/** + * dpll_pin_unregister - deregister dpll pin from dpll device + * @dpll: registered dpll pointer + * @pin: pointer to a pin + * @ops: ops for a dpll pin + * @priv: pointer to private information of owner + * + * Note: It does not free the memory + */ +void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv) +{ + if (WARN_ON(xa_empty(&dpll->pin_refs))) + return; + + mutex_lock(&dpll_xa_lock); + __dpll_pin_unregister(dpll, pin, ops, priv); + mutex_unlock(&dpll_xa_lock); +} +EXPORT_SYMBOL_GPL(dpll_pin_unregister); + +/** + * dpll_pin_on_pin_register - register a pin with a parent pin + * @parent: pointer to a parent pin + * @pin: pointer to a pin + * @ops: ops for a dpll pin + * @priv: pointer to private information of owner + * @rclk_device: pointer to recovered clock device + * + * Register a pin with a parent pin, create references between them and + * between newly registered pin and dplls connected with a parent pin. + * + * Return: + * * 0 on success + * * -EINVAL missing pin or parent + * * -ENOMEM failed allocation + * * -EPERM if parent is not allowed + */ +int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, + struct device *rclk_device) +{ + struct dpll_pin_ref *ref; + unsigned long i, stop; + int ret; + + if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX)) + return -EINVAL; + ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); + if (ret) + goto unlock; + refcount_inc(&pin->refcount); + xa_for_each(&parent->dpll_refs, i, ref) { + mutex_lock(&dpll_xa_lock); + ret = __dpll_pin_register(ref->dpll, pin, ops, priv, + rclk_device ? + dev_name(rclk_device) : NULL); + mutex_unlock(&dpll_xa_lock); + if (ret) { + stop = i; + goto dpll_unregister; + } + dpll_pin_parent_notify(ref->dpll, pin, parent, DPLL_A_PIN_IDX); + } + + return ret; + +dpll_unregister: + xa_for_each(&parent->dpll_refs, i, ref) { + if (i < stop) { + mutex_lock(&dpll_xa_lock); + __dpll_pin_unregister(ref->dpll, pin, ops, priv); + mutex_unlock(&dpll_xa_lock); + } + } + refcount_dec(&pin->refcount); + dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); +unlock: + return ret; +} +EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register); + +/** + * dpll_pin_on_pin_unregister - deregister dpll pin from a parent pin + * @parent: pointer to a parent pin + * @pin: pointer to a pin + * @ops: ops for a dpll pin + * @priv: pointer to private information of owner + * + * Note: It does not free the memory + */ +void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv) +{ + struct dpll_pin_ref *ref; + unsigned long i; + + mutex_lock(&dpll_xa_lock); + dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); + refcount_dec(&pin->refcount); + xa_for_each(&pin->dpll_refs, i, ref) { + __dpll_pin_unregister(ref->dpll, pin, ops, priv); + dpll_pin_parent_notify(ref->dpll, pin, parent, + DPLL_A_PIN_IDX); + } + mutex_unlock(&dpll_xa_lock); +} +EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister); + +static struct dpll_device_registration * +dpll_device_registration_first(struct dpll_device *dpll) +{ + struct dpll_device_registration *reg; + + reg = list_first_entry_or_null((struct list_head *) &dpll->registration_list, + struct dpll_device_registration, list); + WARN_ON(!reg); + return reg; +} + +/** + * dpll_priv - get the dpll device private owner data + * @dpll: registered dpll pointer + * + * Return: pointer to the data + */ +void *dpll_priv(const struct dpll_device *dpll) +{ + struct dpll_device_registration *reg; + + reg = dpll_device_registration_first((struct dpll_device *) dpll); + return reg->priv; +} + +const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll) +{ + struct dpll_device_registration *reg; + + reg = dpll_device_registration_first(dpll); + return reg->ops; +} + +static struct dpll_pin_registration * +dpll_pin_registration_first(struct dpll_pin_ref *ref) +{ + struct dpll_pin_registration *reg; + + reg = list_first_entry_or_null(&ref->registration_list, + struct dpll_pin_registration, list); + WARN_ON(!reg); + return reg; +} + +/** + * dpll_pin_on_dpll_priv - get the dpll device private owner data + * @dpll: registered dpll pointer + * @pin: pointer to a pin + * + * Return: pointer to the data + */ +void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, + const struct dpll_pin *pin) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + + ref = xa_load((struct xarray *)&dpll->pin_refs, pin->pin_idx); + if (!ref) + return NULL; + reg = dpll_pin_registration_first(ref); + return reg->priv; +} + +/** + * dpll_pin_on_pin_priv - get the dpll pin private owner data + * @parent: pointer to a parent pin + * @pin: pointer to a pin + * + * Return: pointer to the data + */ +void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, + const struct dpll_pin *pin) +{ + struct dpll_pin_registration *reg; + struct dpll_pin_ref *ref; + + ref = xa_load((struct xarray *)&pin->parent_refs, parent->pin_idx); + if (!ref) + return NULL; + reg = dpll_pin_registration_first(ref); + return reg->priv; +} + +const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref) +{ + struct dpll_pin_registration *reg; + + reg = dpll_pin_registration_first(ref); + return reg->ops; +} + +static int __init dpll_init(void) +{ + int ret; + + ret = dpll_netlink_init(); + if (ret) + goto error; + + return 0; + +error: + mutex_destroy(&dpll_xa_lock); + return ret; +} +subsys_initcall(dpll_init); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h new file mode 100644 index 000000000000..e905c1088568 --- /dev/null +++ b/drivers/dpll/dpll_core.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + */ + +#ifndef __DPLL_CORE_H__ +#define __DPLL_CORE_H__ + +#include +#include +#include +#include "dpll_netlink.h" + +#define DPLL_REGISTERED XA_MARK_1 + +struct dpll_device_registration { + struct list_head list; + const struct dpll_device_ops *ops; + void *priv; +}; + +/** + * struct dpll_device - structure for a DPLL device + * @id: unique id number for each device + * @dev_driver_id: id given by dev driver + * @clock_id: unique identifier (clock_id) of a dpll + * @module: module of creator + * @dev: struct device for this dpll device + * @parent: parent device + * @ops: operations this &dpll_device supports + * @lock: mutex to serialize operations + * @type: type of a dpll + * @pins: list of pointers to pins registered with this dpll + * @mode_supported_mask: mask of supported modes + * @refcount: refcount + * @priv: pointer to private information of owner + **/ +struct dpll_device { + u32 id; + u32 device_idx; + u64 clock_id; + struct module *module; + struct device dev; + struct device *parent; + enum dpll_type type; + struct xarray pin_refs; + unsigned long mode_supported_mask; + refcount_t refcount; + struct list_head registration_list; +}; + +/** + * struct dpll_pin - structure for a dpll pin + * @idx: unique idx given by alloc on global pin's XA + * @dev_driver_id: id given by dev driver + * @clock_id: clock_id of creator + * @module: module of creator + * @dpll_refs: hold referencees to dplls that pin is registered with + * @pin_refs: hold references to pins that pin is registered with + * @prop: properties given by registerer + * @rclk_dev_name: holds name of device when pin can recover clock from it + * @refcount: refcount + **/ +struct dpll_pin { + u32 id; + u32 pin_idx; + u64 clock_id; + struct module *module; + struct xarray dpll_refs; + struct xarray parent_refs; + struct dpll_pin_properties prop; + char *rclk_dev_name; + refcount_t refcount; +}; + +struct dpll_pin_registration { + struct list_head list; + const struct dpll_pin_ops *ops; + void *priv; +}; + +/** + * struct dpll_pin_ref - structure for referencing either dpll or pins + * @dpll: pointer to a dpll + * @pin: pointer to a pin + * @registration_list list of ops and priv data registered with the ref + * @refcount: refcount + **/ +struct dpll_pin_ref { + union { + struct dpll_device *dpll; + struct dpll_pin *pin; + }; + struct list_head registration_list; + refcount_t refcount; +}; + +void *dpll_priv(const struct dpll_device *dpll); +void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, + const struct dpll_pin *pin); +void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, + const struct dpll_pin *pin); + +const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll); +struct dpll_device *dpll_device_get_by_id(int id); +struct dpll_device *dpll_device_get_by_name(const char *bus_name, + const char *dev_name); +const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref); +struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs); +extern struct xarray dpll_device_xa; +extern struct xarray dpll_pin_xa; +extern struct mutex dpll_xa_lock; +#endif diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c new file mode 100644 index 000000000000..1eb0b4a2fce4 --- /dev/null +++ b/drivers/dpll/dpll_netlink.c @@ -0,0 +1,972 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic netlink for DPLL management framework + * + * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + * + */ +#include +#include +#include +#include "dpll_core.h" +#include "dpll_nl.h" +#include + +struct dpll_dump_ctx { + unsigned long idx; +}; + +static struct dpll_dump_ctx *dpll_dump_context(struct netlink_callback *cb) +{ + return (struct dpll_dump_ctx *)cb->ctx; +} + +static int +dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll) +{ + if (nla_put_u32(msg, DPLL_A_ID, dpll->id)) + return -EMSGSIZE; + if (nla_put_string(msg, DPLL_A_BUS_NAME, dev_bus_name(&dpll->dev))) + return -EMSGSIZE; + if (nla_put_string(msg, DPLL_A_DEV_NAME, dev_name(&dpll->dev))) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_mode(struct sk_buff *msg, struct dpll_device *dpll, + struct netlink_ext_ack *extack) +{ + const struct dpll_device_ops *ops = dpll_device_ops(dpll); + enum dpll_mode mode; + + if (WARN_ON(!ops->mode_get)) + return -EOPNOTSUPP; + if (ops->mode_get(dpll, dpll_priv(dpll), &mode, extack)) + return -EFAULT; + if (nla_put_u8(msg, DPLL_A_MODE, mode)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll, + struct netlink_ext_ack *extack) +{ + const struct dpll_device_ops *ops = dpll_device_ops(dpll); + enum dpll_lock_status status; + + if (WARN_ON(!ops->lock_status_get)) + return -EOPNOTSUPP; + if (ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack)) + return -EFAULT; + if (nla_put_u8(msg, DPLL_A_LOCK_STATUS, status)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll, + struct netlink_ext_ack *extack) +{ + const struct dpll_device_ops *ops = dpll_device_ops(dpll); + s32 temp; + + if (!ops->temp_get) + return -EOPNOTSUPP; + if (ops->temp_get(dpll, dpll_priv(dpll), &temp, extack)) + return -EFAULT; + if (nla_put_s32(msg, DPLL_A_TEMP, temp)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_pin_prio(struct sk_buff *msg, const struct dpll_pin *pin, + struct dpll_pin_ref *ref, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + const struct dpll_device *dpll = ref->dpll; + u32 prio; + + if (!ops->prio_get) + return -EOPNOTSUPP; + if (ops->prio_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), &prio, extack)) + return -EFAULT; + if (nla_put_u32(msg, DPLL_A_PIN_PRIO, prio)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, const struct dpll_pin *pin, + struct dpll_pin_ref *ref, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + const struct dpll_device *dpll = ref->dpll; + enum dpll_pin_state state; + + if (!ops->state_on_dpll_get) + return -EOPNOTSUPP; + if (ops->state_on_dpll_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), &state, extack)) + return -EFAULT; + if (nla_put_u8(msg, DPLL_A_PIN_STATE, state)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_pin_direction(struct sk_buff *msg, const struct dpll_pin *pin, + struct dpll_pin_ref *ref, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + const struct dpll_device *dpll = ref->dpll; + enum dpll_pin_direction direction; + + if (!ops->direction_get) + return -EOPNOTSUPP; + if (ops->direction_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), &direction, extack)) + return -EFAULT; + if (nla_put_u8(msg, DPLL_A_PIN_DIRECTION, direction)) + return -EMSGSIZE; + + return 0; +} + +static int +dpll_msg_add_pin_freq(struct sk_buff *msg, const struct dpll_pin *pin, + struct dpll_pin_ref *ref, struct netlink_ext_ack *extack, + bool dump_freq_supported) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + const struct dpll_device *dpll = ref->dpll; + struct nlattr *nest; + u64 freq; + int fs; + + if (!ops->frequency_get) + return -EOPNOTSUPP; + if (ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), &freq, extack)) + return -EFAULT; + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq, 0)) + return -EMSGSIZE; + if (!dump_freq_supported) + return 0; + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) { + nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); + if (!nest) + return -EMSGSIZE; + freq = pin->prop.freq_supported[fs].min; + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), + &freq, 0)) { + nla_nest_cancel(msg, nest); + return -EMSGSIZE; + } + freq = pin->prop.freq_supported[fs].max; + if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), + &freq, 0)) { + nla_nest_cancel(msg, nest); + return -EMSGSIZE; + } + nla_nest_end(msg, nest); + } + + return 0; +} + +static int +dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, + struct netlink_ext_ack *extack) +{ + enum dpll_pin_state state; + struct dpll_pin_ref *ref; + struct dpll_pin *ppin; + struct nlattr *nest; + unsigned long index; + int ret; + + xa_for_each(&pin->parent_refs, index, ref) { + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + + ppin = ref->pin; + + if (WARN_ON(!ops->state_on_pin_get)) + return -EFAULT; + ret = ops->state_on_pin_get(pin, + dpll_pin_on_pin_priv(ppin, pin), + ppin, &state, extack); + if (ret) + return -EFAULT; + nest = nla_nest_start(msg, DPLL_A_PIN_PARENT); + if (!nest) + return -EMSGSIZE; + if (nla_put_u32(msg, DPLL_A_PIN_PARENT_IDX, ppin->pin_idx)) { + ret = -EMSGSIZE; + goto nest_cancel; + } + if (nla_put_u8(msg, DPLL_A_PIN_STATE, state)) { + ret = -EMSGSIZE; + goto nest_cancel; + } + nla_nest_end(msg, nest); + } + + return 0; + +nest_cancel: + nla_nest_cancel(msg, nest); + return ret; +} + +static int +dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, + struct netlink_ext_ack *extack) +{ + struct dpll_pin_ref *ref; + struct nlattr *attr; + unsigned long index; + int ret; + + xa_for_each(&pin->dpll_refs, index, ref) { + attr = nla_nest_start(msg, DPLL_A_DEVICE); + if (!attr) + return -EMSGSIZE; + ret = dpll_msg_add_dev_handle(msg, ref->dpll); + if (ret) + goto nest_cancel; + ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, extack); + if (ret && ret != -EOPNOTSUPP) + goto nest_cancel; + ret = dpll_msg_add_pin_prio(msg, pin, ref, extack); + if (ret && ret != -EOPNOTSUPP) + goto nest_cancel; + nla_nest_end(msg, attr); + } + + return 0; + +nest_cancel: + nla_nest_end(msg, attr); + return ret; +} + +static int +dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, + struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) +{ + int ret; + + if (nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) + return -EMSGSIZE; + if (nla_put_string(msg, DPLL_A_PIN_LABEL, pin->prop.label)) + return -EMSGSIZE; + if (nla_put_u8(msg, DPLL_A_PIN_TYPE, pin->prop.type)) + return -EMSGSIZE; + if (nla_put_u32(msg, DPLL_A_PIN_DPLL_CAPS, pin->prop.capabilities)) + return -EMSGSIZE; + ret = dpll_msg_add_pin_direction(msg, pin, ref, extack); + if (ret) + return ret; + ret = dpll_msg_add_pin_freq(msg, pin, ref, extack, true); + if (ret && ret != -EOPNOTSUPP) + return ret; + if (pin->rclk_dev_name) + if (nla_put_string(msg, DPLL_A_PIN_RCLK_DEVICE, + pin->rclk_dev_name)) + return -EMSGSIZE; + return 0; +} + +static int +__dpll_cmd_pin_dump_one(struct sk_buff *msg, struct dpll_pin *pin, + struct netlink_ext_ack *extack) +{ + struct dpll_pin_ref *ref; + int ret; + + ref = dpll_xa_ref_dpll_first(&pin->dpll_refs); + if (!ref) + return -EFAULT; + ret = dpll_cmd_pin_fill_details(msg, pin, ref, extack); + if (ret) + return ret; + ret = dpll_msg_add_pin_parents(msg, pin, extack); + if (ret) + return ret; + if (!xa_empty(&pin->dpll_refs)) { + ret = dpll_msg_add_pin_dplls(msg, pin, extack); + if (ret) + return ret; + } + + return 0; +} + +static int +dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, + struct netlink_ext_ack *extack) +{ + enum dpll_mode mode; + int ret; + + ret = dpll_msg_add_dev_handle(msg, dpll); + if (ret) + return ret; + ret = dpll_msg_add_temp(msg, dpll, extack); + if (ret && ret != -EOPNOTSUPP) + return ret; + ret = dpll_msg_add_lock_status(msg, dpll, extack); + if (ret) + return ret; + ret = dpll_msg_add_mode(msg, dpll, extack); + if (ret) + return ret; + for (mode = DPLL_MODE_UNSPEC + 1; mode <= DPLL_MODE_MAX; mode++) + if (test_bit(mode, &dpll->mode_supported_mask)) + if (nla_put_s32(msg, DPLL_A_MODE_SUPPORTED, mode)) + return -EMSGSIZE; + if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), + &dpll->clock_id, 0)) + return -EMSGSIZE; + if (nla_put_u8(msg, DPLL_A_TYPE, dpll->type)) + return -EMSGSIZE; + + return ret; +} + +static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) +{ + int fs; + + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) + if (freq >= pin->prop.freq_supported[fs].min && + freq <= pin->prop.freq_supported[fs].max) + return true; + return false; +} + +static int +dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, + struct netlink_ext_ack *extack) +{ + u64 freq = nla_get_u64(a); + struct dpll_pin_ref *ref; + unsigned long i; + int ret; + + if (!dpll_pin_is_freq_supported(pin, freq)) + return -EINVAL; + + xa_for_each(&pin->dpll_refs, i, ref) { + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + struct dpll_device *dpll = ref->dpll; + + ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin), + dpll, dpll_priv(dpll), freq, extack); + if (ret) + return -EFAULT; + dpll_pin_notify(dpll, pin, DPLL_A_PIN_FREQUENCY); + } + + return 0; +} + +static int +dpll_pin_on_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, + u32 parent_idx, enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops; + struct dpll_pin_ref *pin_ref, *parent_ref; + + if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop.capabilities)) + return -EOPNOTSUPP; + parent_ref = xa_load(&pin->parent_refs, parent_idx); + // dpll_pin_get_by_idx(dpll, parent_idx); + if (!parent_ref) + return -EINVAL; + pin_ref = xa_load(&dpll->pin_refs, pin->pin_idx); + if (!pin_ref) + return -EINVAL; + ops = dpll_pin_ops(pin_ref); + if (!ops->state_on_pin_set) + return -EOPNOTSUPP; + if (ops->state_on_pin_set(pin_ref->pin, + dpll_pin_on_pin_priv(parent_ref->pin, + pin_ref->pin), + parent_ref->pin, state, extack)) + return -EFAULT; + dpll_pin_parent_notify(dpll, pin_ref->pin, parent_ref->pin, + DPLL_A_PIN_STATE); + + return 0; +} + +static int +dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops; + struct dpll_pin_ref *ref; + + if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop.capabilities)) + return -EOPNOTSUPP; + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EFAULT; + ops = dpll_pin_ops(ref); + if (!ops->state_on_dpll_set) + return -EOPNOTSUPP; + if (ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), state, extack)) + return -EINVAL; + dpll_pin_notify(dpll, pin, DPLL_A_PIN_STATE); + + return 0; +} + +static int +dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, + struct nlattr *prio_attr, struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops; + struct dpll_pin_ref *ref; + u32 prio = nla_get_u8(prio_attr); + + if (!(DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE & pin->prop.capabilities)) + return -EOPNOTSUPP; + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EFAULT; + ops = dpll_pin_ops(ref); + if (!ops->prio_set) + return -EOPNOTSUPP; + if (ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, + dpll_priv(dpll), prio, extack)) + return -EINVAL; + dpll_pin_notify(dpll, pin, DPLL_A_PIN_PRIO); + + return 0; +} + +static int +dpll_pin_direction_set(struct dpll_pin *pin, struct nlattr *a, + struct netlink_ext_ack *extack) +{ + enum dpll_pin_direction direction = nla_get_u8(a); + struct dpll_pin_ref *ref; + unsigned long i; + + if (!(DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE & pin->prop.capabilities)) + return -EOPNOTSUPP; + + xa_for_each(&pin->dpll_refs, i, ref) { + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + struct dpll_device *dpll = ref->dpll; + + if (ops->direction_set(pin, dpll_pin_on_dpll_priv(dpll, pin), + dpll, dpll_priv(dpll), direction, + extack)) + return -EFAULT; + dpll_pin_notify(dpll, pin, DPLL_A_PIN_DIRECTION); + } + + return 0; +} + +static int +dpll_pin_set_from_nlattr(struct dpll_device *dpll, + struct dpll_pin *pin, struct genl_info *info) +{ + enum dpll_pin_state state = DPLL_PIN_STATE_UNSPEC; + bool parent_present = false; + int rem, ret = -EINVAL; + struct nlattr *a; + u32 parent_idx; + + nla_for_each_attr(a, genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), rem) { + switch (nla_type(a)) { + case DPLL_A_PIN_FREQUENCY: + ret = dpll_pin_freq_set(pin, a, info->extack); + if (ret) + return ret; + break; + case DPLL_A_PIN_DIRECTION: + ret = dpll_pin_direction_set(pin, a, info->extack); + if (ret) + return ret; + break; + case DPLL_A_PIN_PRIO: + ret = dpll_pin_prio_set(dpll, pin, a, info->extack); + if (ret) + return ret; + break; + case DPLL_A_PIN_PARENT_IDX: + parent_present = true; + parent_idx = nla_get_u32(a); + break; + case DPLL_A_PIN_STATE: + state = nla_get_u8(a); + break; + default: + break; + } + } + if (state != DPLL_PIN_STATE_UNSPEC) { + if (!parent_present) { + ret = dpll_pin_state_set(dpll, pin, state, + info->extack); + if (ret) + return ret; + } else { + ret = dpll_pin_on_pin_state_set(dpll, pin, parent_idx, + state, info->extack); + if (ret) + return ret; + } + } + + return ret; +} + +int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_device *dpll = info->user_ptr[0]; + struct dpll_pin *pin = info->user_ptr[1]; + + return dpll_pin_set_from_nlattr(dpll, pin, info); +} + +int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_pin *pin = info->user_ptr[1]; + struct sk_buff *msg; + struct nlattr *hdr; + int ret; + + if (!pin) + return -ENODEV; + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, + DPLL_CMD_PIN_GET); + if (!hdr) + return -EMSGSIZE; + ret = __dpll_cmd_pin_dump_one(msg, pin, info->extack); + if (ret) { + nlmsg_free(msg); + return ret; + } + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); +} + +int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct dpll_dump_ctx *ctx = dpll_dump_context(cb); + struct dpll_pin *pin; + struct nlattr *hdr; + unsigned long i; + int ret = 0; + + xa_for_each_start(&dpll_pin_xa, i, pin, ctx->idx) { + if (xa_empty(&pin->dpll_refs)) + continue; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + &dpll_nl_family, NLM_F_MULTI, + DPLL_CMD_PIN_GET); + if (!hdr) { + ret = -EMSGSIZE; + break; + } + ret = __dpll_cmd_pin_dump_one(skb, pin, cb->extack); + if (ret) { + genlmsg_cancel(skb, hdr); + break; + } + genlmsg_end(skb, hdr); + } + if (ret == -EMSGSIZE) { + ctx->idx = i; + return skb->len; + } + return ret; +} + +static int +dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info) +{ + const struct dpll_device_ops *ops = dpll_device_ops(dpll); + struct nlattr *attr; + enum dpll_mode mode; + int rem, ret = 0; + + nla_for_each_attr(attr, genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), rem) { + switch (nla_type(attr)) { + case DPLL_A_MODE: + mode = nla_get_u8(attr); + + ret = ops->mode_set(dpll, dpll_priv(dpll), mode, + info->extack); + if (ret) + return ret; + break; + default: + break; + } + } + + return ret; +} + +int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_device *dpll = info->user_ptr[0]; + + return dpll_set_from_nlattr(dpll, info); +} + +int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_device *dpll = info->user_ptr[0]; + struct sk_buff *msg; + struct nlattr *hdr; + int ret; + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, + DPLL_CMD_DEVICE_GET); + if (!hdr) + return -EMSGSIZE; + + ret = dpll_device_get_one(dpll, msg, info->extack); + if (ret) { + nlmsg_free(msg); + return ret; + } + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); +} + +int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct dpll_dump_ctx *ctx = dpll_dump_context(cb); + struct dpll_device *dpll; + struct nlattr *hdr; + unsigned long i; + int ret = 0; + + xa_for_each_start(&dpll_device_xa, i, dpll, ctx->idx) { + if (!xa_get_mark(&dpll_device_xa, i, DPLL_REGISTERED)) + continue; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, &dpll_nl_family, + NLM_F_MULTI, DPLL_CMD_DEVICE_GET); + if (!hdr) { + ret = -EMSGSIZE; + break; + } + ret = dpll_device_get_one(dpll, skb, cb->extack); + if (ret) { + genlmsg_cancel(skb, hdr); + break; + } + genlmsg_end(skb, hdr); + } + if (ret == -EMSGSIZE) { + ctx->idx = i; + return skb->len; + } + return ret; +} + +int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct dpll_device *dpll_id = NULL; + u32 id; + + if (!info->attrs[DPLL_A_ID]) + return -EINVAL; + + mutex_lock(&dpll_xa_lock); + id = nla_get_u32(info->attrs[DPLL_A_ID]); + + dpll_id = dpll_device_get_by_id(id); + if (!dpll_id) + goto unlock; + info->user_ptr[0] = dpll_id; + return 0; +unlock: + mutex_unlock(&dpll_xa_lock); + return -ENODEV; +} + +void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + mutex_unlock(&dpll_xa_lock); +} + +int dpll_pre_dumpit(struct netlink_callback *cb) +{ + mutex_lock(&dpll_xa_lock); + + return 0; +} + +int dpll_post_dumpit(struct netlink_callback *cb) +{ + mutex_unlock(&dpll_xa_lock); + + return 0; +} + +int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + int ret = dpll_pre_doit(ops, skb, info); + struct dpll_pin_ref *pin_ref; + struct dpll_device *dpll; + + if (ret) + return ret; + dpll = info->user_ptr[0]; + if (!info->attrs[DPLL_A_PIN_IDX]) { + ret = -EINVAL; + goto unlock_dev; + } + pin_ref = xa_load(&dpll->pin_refs, + nla_get_u32(info->attrs[DPLL_A_PIN_IDX])); + if (!pin_ref) { + ret = -ENODEV; + goto unlock_dev; + } + info->user_ptr[1] = pin_ref->pin; + + return 0; + +unlock_dev: + mutex_unlock(&dpll_xa_lock); + return ret; +} + +void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + dpll_post_doit(ops, skb, info); +} + +int dpll_pin_pre_dumpit(struct netlink_callback *cb) +{ + return dpll_pre_dumpit(cb); +} + +int dpll_pin_post_dumpit(struct netlink_callback *cb) +{ + return dpll_post_dumpit(cb); +} + +static int +dpll_event_device_change(struct sk_buff *msg, struct dpll_device *dpll, + struct dpll_pin *pin, struct dpll_pin *parent, + enum dplla attr) +{ + int ret = dpll_msg_add_dev_handle(msg, dpll); + struct dpll_pin_ref *ref = NULL; + enum dpll_pin_state state; + + if (ret) + return ret; + if (pin && nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) + return -EMSGSIZE; + + switch (attr) { + case DPLL_A_MODE: + ret = dpll_msg_add_mode(msg, dpll, NULL); + break; + case DPLL_A_LOCK_STATUS: + ret = dpll_msg_add_lock_status(msg, dpll, NULL); + break; + case DPLL_A_TEMP: + ret = dpll_msg_add_temp(msg, dpll, NULL); + break; + case DPLL_A_PIN_FREQUENCY: + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EFAULT; + ret = dpll_msg_add_pin_freq(msg, pin, ref, NULL, false); + break; + case DPLL_A_PIN_PRIO: + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EFAULT; + ret = dpll_msg_add_pin_prio(msg, pin, ref, NULL); + break; + case DPLL_A_PIN_STATE: + if (parent) { + const struct dpll_pin_ops *ops; + void *priv = dpll_pin_on_pin_priv(parent, pin); + + ref = xa_load(&pin->parent_refs, parent->pin_idx); + if (!ref) + return -EFAULT; + ops = dpll_pin_ops(ref); + if (!ops->state_on_pin_get) + return -EOPNOTSUPP; + ret = ops->state_on_pin_get(pin, priv, parent, + &state, NULL); + if (ret) + return ret; + if (nla_put_u32(msg, DPLL_A_PIN_PARENT_IDX, + parent->pin_idx)) + return -EMSGSIZE; + } else { + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EFAULT; + ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, + NULL); + if (ret) + return ret; + } + break; + default: + break; + } + + return ret; +} + +static int +dpll_send_event_create(enum dpll_event event, struct dpll_device *dpll) +{ + struct sk_buff *msg; + int ret = -EMSGSIZE; + void *hdr; + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); + if (!hdr) + goto out_free_msg; + + ret = dpll_msg_add_dev_handle(msg, dpll); + if (ret) + goto out_cancel_msg; + genlmsg_end(msg, hdr); + genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); + + return 0; + +out_cancel_msg: + genlmsg_cancel(msg, hdr); +out_free_msg: + nlmsg_free(msg); + + return ret; +} + +static int +dpll_send_event_change(struct dpll_device *dpll, struct dpll_pin *pin, + struct dpll_pin *parent, enum dplla attr) +{ + struct sk_buff *msg; + int ret = -EMSGSIZE; + void *hdr; + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, + DPLL_EVENT_DEVICE_CHANGE); + if (!hdr) + goto out_free_msg; + + ret = dpll_event_device_change(msg, dpll, pin, parent, attr); + if (ret) + goto out_cancel_msg; + genlmsg_end(msg, hdr); + genlmsg_multicast(&dpll_nl_family, msg, 0, 0, GFP_KERNEL); + + return 0; + +out_cancel_msg: + genlmsg_cancel(msg, hdr); +out_free_msg: + nlmsg_free(msg); + + return ret; +} + +int dpll_notify_device_create(struct dpll_device *dpll) +{ + return dpll_send_event_create(DPLL_EVENT_DEVICE_CREATE, dpll); +} + +int dpll_notify_device_delete(struct dpll_device *dpll) +{ + return dpll_send_event_create(DPLL_EVENT_DEVICE_DELETE, dpll); +} + +int dpll_device_notify(struct dpll_device *dpll, enum dplla attr) +{ + if (WARN_ON(!dpll)) + return -EINVAL; + + return dpll_send_event_change(dpll, NULL, NULL, attr); +} +EXPORT_SYMBOL_GPL(dpll_device_notify); + +int dpll_pin_notify(struct dpll_device *dpll, struct dpll_pin *pin, + enum dplla attr) +{ + return dpll_send_event_change(dpll, pin, NULL, attr); +} +EXPORT_SYMBOL_GPL(dpll_pin_notify); + +int dpll_pin_parent_notify(struct dpll_device *dpll, struct dpll_pin *pin, + struct dpll_pin *parent, enum dplla attr) +{ + return dpll_send_event_change(dpll, pin, parent, attr); +} + +int __init dpll_netlink_init(void) +{ + return genl_register_family(&dpll_nl_family); +} + +void dpll_netlink_finish(void) +{ + genl_unregister_family(&dpll_nl_family); +} + +void __exit dpll_netlink_fini(void) +{ + dpll_netlink_finish(); +} diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h new file mode 100644 index 000000000000..952e0335595e --- /dev/null +++ b/drivers/dpll/dpll_netlink.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + */ + +/** + * dpll_notify_device_create - notify that the device has been created + * @dpll: registered dpll pointer + * + * Return: 0 if succeeds, error code otherwise. + */ +int dpll_notify_device_create(struct dpll_device *dpll); + + +/** + * dpll_notify_device_delete - notify that the device has been deleted + * @dpll: registered dpll pointer + * + * Return: 0 if succeeds, error code otherwise. + */ +int dpll_notify_device_delete(struct dpll_device *dpll); + +int dpll_pin_parent_notify(struct dpll_device *dpll, struct dpll_pin *pin, + struct dpll_pin *parent, enum dplla attr); + +int __init dpll_netlink_init(void); +void dpll_netlink_finish(void); diff --git a/include/linux/dpll.h b/include/linux/dpll.h new file mode 100644 index 000000000000..5194efaf55a8 --- /dev/null +++ b/include/linux/dpll.h @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Intel and affiliates + */ + +#ifndef __DPLL_H__ +#define __DPLL_H__ + +#include +#include +#include + +struct dpll_device; +struct dpll_pin; + +struct dpll_device_ops { + int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_mode *mode, struct netlink_ext_ack *extack); + int (*mode_set)(const struct dpll_device *dpll, void *dpll_priv, + const enum dpll_mode mode, + struct netlink_ext_ack *extack); + bool (*mode_supported)(const struct dpll_device *dpll, void *dpll_priv, + const enum dpll_mode mode, + struct netlink_ext_ack *extack); + int (*source_pin_idx_get)(const struct dpll_device *dpll, + void *dpll_priv, + u32 *pin_idx, + struct netlink_ext_ack *extack); + int (*lock_status_get)(const struct dpll_device *dpll, void *dpll_priv, + enum dpll_lock_status *status, + struct netlink_ext_ack *extack); + int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv, + s32 *temp, struct netlink_ext_ack *extack); +}; + +struct dpll_pin_ops { + int (*frequency_set)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + const u64 frequency, + struct netlink_ext_ack *extack); + int (*frequency_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack); + int (*direction_set)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + const enum dpll_pin_direction direction, + struct netlink_ext_ack *extack); + int (*direction_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack); + int (*state_on_pin_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *parent_pin, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack); + int (*state_on_dpll_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, enum dpll_pin_state *state, + struct netlink_ext_ack *extack); + int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *parent_pin, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack); + int (*state_on_dpll_set)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack); + int (*prio_get)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 *prio, struct netlink_ext_ack *extack); + int (*prio_set)(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + const u32 prio, struct netlink_ext_ack *extack); +}; + +struct dpll_pin_frequency { + u64 min; + u64 max; +}; + +#define DPLL_PIN_FREQUENCY_RANGE(_min, _max) \ + { \ + .min = _min, \ + .max = _max, \ + } + +#define DPLL_PIN_FREQUENCY(_val) DPLL_PIN_FREQUENCY_RANGE(_val, _val) +#define DPLL_PIN_FREQUENCY_1PPS \ + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_1_HZ) +#define DPLL_PIN_FREQUENCY_10MHZ \ + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_MHZ) +#define DPLL_PIN_FREQUENCY_IRIG_B \ + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_10_KHZ) +#define DPLL_PIN_FREQUENCY_DCF77 \ + DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_77_5_KHZ) + +struct dpll_pin_properties { + const char *label; + enum dpll_pin_type type; + unsigned long capabilities; + u32 freq_supported_num; + struct dpll_pin_frequency *freq_supported; +}; + +/** + * dpll_device_get - find or create dpll_device object + * @clock_id: a system unique number for a device + * @dev_driver_id: index of dpll device on parent device + * @module: register module + * + * Returns: + * * pointer to initialized dpll - success + * * NULL - memory allocation fail + */ +struct dpll_device +*dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module); + +/** + * dpll_device_put - caller drops reference to the device, free resources + * @dpll: dpll device pointer + * + * If all dpll_device_get callers drops their reference, the dpll device + * resources are freed. + */ +void dpll_device_put(struct dpll_device *dpll); + +/** + * dpll_device_register - register device, make it visible in the subsystem. + * @dpll: reference previously allocated with dpll_device_get + * @type: type of dpll + * @ops: callbacks + * @priv: private data of registerer + * @owner: device struct of the owner + * + */ +int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, + const struct dpll_device_ops *ops, void *priv, + struct device *owner); + +/** + * dpll_device_unregister - deregister registered dpll + * @dpll: pointer to dpll + * @ops: ops for a dpll device + * @priv: pointer to private information of owner + * + * Unregister the dpll from the subsystem, make it unavailable for netlink + * API users. + */ +void dpll_device_unregister(struct dpll_device *dpll, + const struct dpll_device_ops *ops, void *priv); + +/** + * dpll_pin_get - get reference or create new pin object + * @clock_id: a system unique number of a device + * @@dev_driver_id: index of dpll device on parent device + * @module: register module + * @pin_prop: constant properities of a pin + * + * find existing pin with given clock_id, @dev_driver_id and module, or create new + * and returen its reference. + * + * Returns: + * * pointer to initialized pin - success + * * NULL - memory allocation fail + */ +struct dpll_pin +*dpll_pin_get(u64 clock_id, u32 dev_driver_id, struct module *module, + const struct dpll_pin_properties *prop); + +/** + * dpll_pin_register - register pin with a dpll device + * @dpll: pointer to dpll object to register pin with + * @pin: pointer to allocated pin object being registered with dpll + * @ops: struct with pin ops callbacks + * @priv: private data pointer passed when calling callback ops + * @rclk_device: pointer to device struct if pin is used for recovery of a clock + * from that device + * + * Register previously allocated pin object with a dpll device. + * + * Return: + * * 0 - if pin was registered with a parent pin, + * * -ENOMEM - failed to allocate memory, + * * -EEXIST - pin already registered with this dpll, + * * -EBUSY - couldn't allocate id for a pin. + */ +int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, + struct device *rclk_device); + +/** + * dpll_pin_unregister - deregister pin from a dpll device + * @dpll: pointer to dpll object to deregister pin from + * @pin: pointer to allocated pin object being deregistered from dpll + * @ops: ops for a dpll pin ops + * @priv: pointer to private information of owner + * + * Deregister previously registered pin object from a dpll device. + * + */ +void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv); + +/** + * dpll_pin_put - drop reference to a pin acquired with dpll_pin_get + * @pin: pointer to allocated pin + * + * Pins shall be deregistered from all dpll devices before putting them, + * otherwise the memory won't be freed. + */ +void dpll_pin_put(struct dpll_pin *pin); + +/** + * dpll_pin_on_pin_register - register a pin to a muxed-type pin + * @parent: parent pin pointer + * @pin: pointer to allocated pin object being registered with a parent pin + * @ops: struct with pin ops callbacks + * @priv: private data pointer passed when calling callback ops + * @rclk_device: pointer to device struct if pin is used for recovery of a clock + * from that device + * + * In case of multiplexed pins, allows registring them under a single + * parent pin. + * + * Return: + * * 0 - if pin was registered with a parent pin, + * * -ENOMEM - failed to allocate memory, + * * -EEXIST - pin already registered with this parent pin, + */ +int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, + struct device *rclk_device); + +/** + * dpll_pin_on_pin_register - register a pin to a muxed-type pin + * @parent: parent pin pointer + * @pin: pointer to allocated pin object being registered with a parent pin + * @ops: struct with pin ops callbacks + * @priv: private data pointer passed when calling callback ops + * @rclk_device: pointer to device struct if pin is used for recovery of a clock + * from that device + * + * In case of multiplexed pins, allows registring them under a single + * parent pin. + * + * Return: + * * 0 - if pin was registered with a parent pin, + * * -ENOMEM - failed to allocate memory, + * * -EEXIST - pin already registered with this parent pin, + */ +void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv); + +/** + * dpll_device_notify - notify on dpll device change + * @dpll: dpll device pointer + * @attr: changed attribute + * + * Broadcast event to the netlink multicast registered listeners. + * + * Return: + * * 0 - success + * * negative - error + */ +int dpll_device_notify(struct dpll_device *dpll, enum dplla attr); + +int dpll_pin_notify(struct dpll_device *dpll, struct dpll_pin *pin, + enum dplla attr); + + + +#endif diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index e188bc189754..75eeaa4396eb 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -111,6 +111,8 @@ enum dpll_pin_direction { #define DPLL_PIN_FREQUENCY_1_HZ 1 #define DPLL_PIN_FREQUENCY_10_MHZ 10000000 +#define DPLL_PIN_FREQUENCY_10_KHZ 10000 +#define DPLL_PIN_FREQUENCY_77_5_KHZ 77500 /** * enum dpll_pin_state - defines possible states of a pin, valid values for From 08a38a17da4df4261717bfa6d99bd9e4c8711c34 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Sat, 11 Mar 2023 17:54:35 -0800 Subject: [PATCH 03/93] dpll: documentation on DPLL subsystem interface Add documentation explaining common netlink interface to configure DPLL devices and monitoring events. Common way to implement DPLL device in a driver is also covered. Signed-off-by: Vadim Fedorenko Signed-off-by: Arkadiusz Kubalewski --- Documentation/dpll.rst | 408 +++++++++++++++++++++++++++++ Documentation/networking/index.rst | 1 + 2 files changed, 409 insertions(+) create mode 100644 Documentation/dpll.rst diff --git a/Documentation/dpll.rst b/Documentation/dpll.rst new file mode 100644 index 000000000000..fba5bc027967 --- /dev/null +++ b/Documentation/dpll.rst @@ -0,0 +1,408 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============================== +The Linux kernel dpll subsystem +=============================== + + +The main purpose of dpll subsystem is to provide general interface +to configure devices that use any kind of Digital PLL and could use +different sources of signal to synchronize to as well as different +types of outputs. +The main interface is NETLINK_GENERIC based protocol with an event +monitoring multicast group defined. + + +Device object +============= +Single dpll device object means single Digital PLL circuit and bunch of +pins connected with it. +It provides its supported working modes and current status to the user +in response to the `do` request of netlink command +``DPLL_CMD_DEVICE_GET`` and list of dplls registered in the subsystem +with `dump` netlink request of same command. +Requesting configuration of dpll device is done with `do` request of +netlink ``DPLL_CMD_DEVICE_SET`` command. + + +Pin object +========== +A pin is amorphic object which represents either source or output, it +could be internal component of the device, as well as externaly +connected. +The number of pins per dpll vary, but usually multiple pins shall be +provided for a single dpll device. +Pin's properties, capabilities and status is provided to the user in +response to `do` request of netlink ``DPLL_CMD_PIN_GET`` command. +It is also possible to list all the pins that were registered in the +system with `dump` request of ``DPLL_CMD_PIN_GET`` command. +Configuration of a pin can be changed by `do` request of netlink +``DPLL_CMD_PIN_SET`` command. + + +Pin selection +============= +In general selected pin (the one which signal is driving the dpll +device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only +one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll +device. + +Pin selection can be done either manualy or automatically, depending on +hardware capabilities and active dpll device work mode +(``DPLL_A_MODE`` attribute). The consequence is that, there are +differences for each mode in terms of available pin states, as well +as for the states the user can request for a dpll device. + +In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive +one of following pin states: +- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device +- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll + device + +In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or +receive one of following pin states: +- ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid + source for automatic selection algorithm +- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as + a valid source for automatic selection algorithm +In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive +pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection +algorithm locks a dpll device with one of the sources. + + +Shared pins +=========== +A single pin object can be registered to multiple dpll devices. +Then there are two groups of configuration knobs: +1) Set on a pin - the configuration affects all dpll devices pin is + registered to. (i.e. ``PIN_FREQUENCY``, ``PIN_DIRECTION``), +2) Set on a pin-dpll tuple - the configuration affects only selected + dpll device. (i.e. PIN_PRIO, PIN_STATE). + + +MUX-type pins +============= +A pin can be MUX-type, it aggregates child pins and serves as a pin +multiplexer. One or more pins are registered with MUX-type instead of +being directly registered to a dpll device. +Pins registered with a MUX-type provide user with additional nested +attribute ``DPLL_A_PIN_PARENT`` for each parent they were registered +with. +If a pin was registered with multiple parent pins, they behave like a +multiple output multiplexer. In this case output of a +``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested +attributes with current state related to each parent, like: + +``'pin': [{ + 'device': [{'bus-name': 'pci', + 'dev-name': '0000:21:00.0_0', 'id': 0}], + 'pin-direction': {'doc': 'pin used as a source of a signal', + 'name': 'source'}, + 'pin-idx': 13, + 'pin-parent': [{'pin-parent-idx': 2, + 'pin-state': {'doc': 'pin disconnected', + 'name': 'disconnected'}}, + {'pin-parent-idx': 3, + 'pin-state': {'doc': 'pin disconnected', + 'name': 'disconnected'}}], + }]`` + +Only one child pin can provide it's signal to the parent MUX-type pin at +a time, the selection is done with requesting change of child pin state +to ``DPLL_PIN_STATE_CONNECTED`` and providing a target MUX-type pin +index value in ``DPLL_A_PARENT_PIN_IDX``. + +Pin priority +============ +Some devices might offer a capability of automatic pin selection mode +(enum value ``DPLL_MODE_AUTOMATIC`` of ``DPLL_A_MODE`` attribute). +Usually such automatic selection is offloaded to the hardware, +which means only pins directly connected to the dpll are capable of +automatic source pin selection. +In automatic selection mode, the user cannot manually select a source +pin for the device, instead the user shall provide all directly +connected pins with a priority ``DPLL_A_PIN_PRIO``, the device would +pick a highest priority valid signal and connect with it. +Child pin of MUX-type is not capable of automatic source pin selection, +in order to configure a source of a MUX-type pin, the user needs to +request desired pin state of the child pin on the parent - it is done +with providing additional attribute for pin set state request - index +of parent pin he wish to propagate its signal to +(``DPLL_A_PARENT_PIN_IDX``). + + +Configuration commands group +============================ + +Configuration commands are used to get or dump information about +registered dpll devices (and pins), as well as set configuration of +device or pins. As dpll device could not be abstract and reflects real +hardware, there is no way to add new dpll device via netlink from user +space and each device should be registered by it's driver. + +All netlink commands require ``GENL_ADMIN_PERM``. This is to prevent +any spamming/D.o.S. from unauthorized userspace applications. + +List of netlink commands with possible attributes +================================================= + +All constants identifying command types use ``DPLL_CMD_`` prefix and +suffix according to command purpose. All attributes use ``DPLL_A_`` +prefix and suffix according to attribute purpose: + + ============================ ======================================= + ``DEVICE_GET`` command to get device info or dump list + of available devices + ``ID`` attr internal dpll device ID + ``DEV_NAME`` attr dpll device name + ``BUS_NAME`` attr dpll device bus name + ``MODE`` attr selection mode + ``MODE_SUPPORTED`` attr available selection modes + ``LOCK_STATUS`` attr internal frequency-lock status + ``TEMP`` attr device temperature information + ``CLOCK_ID`` attr Unique Clock Identifier (EUI-64), + as defined by the IEEE 1588 standard + ``TYPE`` attr type or purpose of dpll device + ``DEVICE_SET`` command to set dpll device configuration + ``ID`` attr internal dpll device index + ``NAME`` attr dpll device name (not required if + dpll device index was provided) + ``MODE`` attr selection mode to configure + ``PIN_GET`` command to get pin info or dump list of + available pins + ``DEVICE`` nest attr for each dpll device pin is + connected with + ``ID`` attr internal dpll device ID + ``DEV_NAME`` attr dpll device name + ``BUS_NAME`` attr dpll device bus name + ``PIN_PRIO`` attr priority of pin on the dpll device + ``PIN_STATE`` attr state of pin on the dpll device + ``PIN_IDX`` attr index of a pin on the dpll device + ``PIN_DESCRIPTION`` attr description provided by driver + ``PIN_TYPE`` attr type of a pin + ``PIN_DIRECTION`` attr direction of a pin + ``PIN_FREQUENCY`` attr current frequency of a pin + ``PIN_FREQUENCY_SUPPORTED`` attr provides supported frequencies + ``PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency in case + pin/dpll supports any frequency + ``PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency in case + pin/dpll supports any frequency + ``PIN_PARENT`` nest attr for each MUX-type parent, that + pin is connected with + ``PIN_PARENT_IDX`` attr index of a parent pin on the dpll + device + ``PIN_STATE`` attr state of a pin on parent pin + ``PIN_RCLK_DEVICE`` attr name of a device, where pin + recovers clock signal from + ``PIN_DPLL_CAPS`` attr bitmask of pin-dpll capabilities + + ``PIN_SET`` command to set pins configuration + ``ID`` attr internal dpll device index + ``BUS_NAME`` attr dpll device name (not required if + dpll device ID was provided) + ``DEV_NAME`` attr dpll device name (not required if + dpll device ID was provided) + ``PIN_IDX`` attr index of a pin on the dpll device + ``PIN_DIRECTION`` attr direction to be set + ``PIN_FREQUENCY`` attr frequency to be set + ``PIN_PRIO`` attr pin priority to be set + ``PIN_STATE`` attr pin state to be set + ``PIN_PARENT_IDX`` attr if provided state is to be set with + parent pin instead of with dpll device + +Netlink dump requests +===================== + +The ``DEVICE_GET`` and ``PIN_GET`` commands are capable of dump type +netlink requests, in which case the response is in the same format as +for their ``do`` request. + + +SET commands format +=================== + +``DEVICE_SET`` - to target a dpll device, the user provides either a +``ID`` or both ``BUS_NAME`` and ``DEV_NAME``, as well as parameter being +configured (``DPLL_A_MODE``). + +``PIN_SET`` - to target a pin user has to provide a ``PIN_IDX``, but +pin does not exist on its own, thus a dpll device must be also targeted +with either a ``ID`` or both ``BUS_NAME`` and ``DEV_NAME`` to which +pin being configured was registered with. Also configured pin parameters +must be added. +If ``PIN_DIRECTION`` or ``PIN_FREQUENCY`` are configured, this affects +all the dpll device they are connected. +If ``PIN_PRIO`` or ``PIN_STATE`` are configured, this affects only +the dpll device being targeted. +If valid ``PIN_PARENT_IDX`` is provided, the set command shall affect +the configuration between a pin and it's parent, which is a +``PIN_STATE``. +In general it is possible to configure multiple parameters at once. + + +Device level configuration pre-defined enums +================================================= + +For all below enum names used for configuration of dpll device use +the ``DPLL_`` prefix. + +Values for ``DPLL_A_LOCK_STATUS`` attribute: + + ============================= ====================================== + ``LOCK_STATUS_UNLOCKED`` dpll device is in freerun, not locked + to any source pin + ``LOCK_STATUS_CALIBRATING`` dpll device calibrates to lock to the + source pin signal + ``LOCK_STATUS_LOCKED`` dpll device is locked to the source + pin frequency + ``LOCK_STATUS_HOLDOVER`` dpll device lost a lock, using its + frequency holdover capabilities + +Values for ``DPLL_A_MODE`` attribute: + + =================== ================================================ + ``MODE_FORCED`` source pin is force-selected by setting pin + state to ``DPLL_PIN_STATE_CONNECTED`` on a dpll + ``MODE_AUTOMATIC`` source pin is auto selected according to + configured pin priorities and source signal + validity + ``MODE_HOLDOVER`` force holdover mode of dpll + ``MODE_FREERUN`` dpll device is driven by supplied system clock + without holdover capabilities + ``MODE_NCO`` similar to FREERUN, with possibility to + numerically control frequency offset + +Values for ``DPLL_A_TYPE`` attribute: + + ============= =================================================== + ``TYPE_PPS`` dpll device used to provide pulse-per-second output + ``TYPE_EEC`` dpll device used to drive ethernet equipment clock + + + +Pin level configuration pre-defined enums +========================================= + +For all below enum names used for configuration of pin use the +``DPLL_PIN_`` prefix. + +Values for ``DPLL_A_PIN_STATE`` attribute: + + ======================= ======================================== + ``STATE_CONNECTED`` Pin used as active source for a dpll + device or for a parent pin + ``STATE_DISCONNECTED`` Pin disconnected from a dpll device or + from a parent pin + ``STATE_SELECTABLE`` Pin enabled for automatic selection + +Values for ``DPLL_A_PIN_DIRECTION`` attribute: + + ======================= ============================== + ``DIRECTION_SOURCE`` Pin used as a source of signal + ``DIRECTION_OUTPUT`` Pin used to output signal + +Values for ``DPLL_A_PIN_TYPE`` attributes: + + ======================== ======================================== + ``TYPE_MUX`` MUX type pin, connected pins shall have + their own types + ``TYPE_EXT`` External pin + ``TYPE_SYNCE_ETH_PORT`` SyncE on Ethernet port + ``TYPE_INT_OSCILLATOR`` Internal Oscillator (i.e. Holdover with + Atomic Clock as a Source) + ``TYPE_GNSS`` GNSS 1PPS source + +Values for ``DPLL_A_PIN_DPLL_CAPS`` attributes: + + ============================= ================================ + ``CAPS_DIRECTION_CAN_CHANGE`` Bit present if direction can change + ``CAPS_PRIORITY_CAN_CHANGE`` Bit present if priority can change + ``CAPS_STATE_CAN_CHANGE`` Bit present if state can change + + +Notifications +============= + +dpll device can provide notifications regarding status changes of the +device, i.e. lock status changes, source/output type changes or alarms. +This is the multicast group that is used to notify user-space apps via +netlink socket: ``DPLL_MCGRP_MONITOR`` + +Notifications messages (attrbiutes use ``DPLL_A`` prefix): + + ========================= ========================================== + ``EVENT_DEVICE_CREATE`` event value new dpll device was created + ``ID`` attr internal dpll device ID + ``DEV_NAME`` attr dpll device name + ``BUS_NAME`` attr dpll device bus name + ``EVENT_DEVICE_DELETE`` event value dpll device was deleted + ``ID`` attr dpll device index + ``EVENT_DEVICE_CHANGE`` event value dpll device attribute has + changed + ``ID`` attr modified dpll device ID + ``PIN_IDX`` attr the modified pin index + +Device change event shall consiste of the attribute and the value that +has changed. + + +Device driver implementation +============================ + +Device is allocated by ``dpll_device_get`` call. Second call with the +same arguments doesn't create new object but provides pointer to +previously created device for given arguments, it also increase refcount +of that object. +Device is deallocated by ``dpll_device_put`` call, which first decreases +the refcount, once refcount is cleared the object is destroyed. + +Device should implement set of operations and register device via +``dpll_device_register`` at which point it becomes available to the +users. Only one driver instance can register a dpll device within dpll +subsytem. Multiple driver instances can obtain reference to it with +``dpll_device_get``. + +The pins are allocated separately with ``dpll_pin_get``, it works +similarly to ``dpll_device_get``. Creates object and the for each call +with the same arguments the object refcount increases. + +Once dpll device is created, allocated pin can be registered with it +with 2 different methods, always providing implemented pin callbacks, +and private data pointer for calling them: +``dpll_pin_register`` - simple registration with a dpll device. +``dpll_pin_on_pin_register`` - register pin with another MUX type pin. + +For different instances of a device driver requiring to find already +registered dpll (i.e. to connect its pins to it) use ``dpll_device_get`` +to obtain proper dpll device pointer. + +The name of dpll device is generated based on registerer provided module +struct pointer, clock_id and device_idx values. +Name is in format: ``%s/%llx/%d`` where arguments are as follows: +``module_name(dpll->module)`` - syscall on parent module struct pointer +``dpll->clock_id`` - registerer given clock id +``dpll->device_idx`` - registerer given device id + +Notifications of adding or removing dpll devices are created within +subsystem itself. +Notifications about registering/deregistering pins are also invoked by +the subsystem. +Notifications about status changes either of dpll device or a pin shall +be requested by device driver with ``dpll_device_notify`` or +``dpll_pin_notify``. + +The device driver using dpll interface is not required to implement all +the callback operation. Nevertheless there are few required to be +implemented. +Required dpll device level callback operations: +- ``.mode_get`` +- ``.lock_status_get`` + +Required pin level callback operations: +- ``.state_get`` +- ``.direction_get`` + +There is no strict requirement to implement all the operations for +each device, every operation handler is checked for existence and +ENOTSUPP is returned in case of absence of specific handler. + diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 5b75c3f7a137..585f84bc3c0c 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -17,6 +17,7 @@ Contents: dsa/index devlink/index caif/index + dpll ethtool-netlink ieee802154 j1939 From 0c1cdd219b4463dd5bfe1fe14544af11bc8ed657 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 11 Jul 2022 02:58:05 +0200 Subject: [PATCH 04/93] ice: add admin commands to access cgu configuration Add firmware admin command to access clock generation unit configuration, it is required to enable Extended PTP and SyncE features in the driver. Add definitions of possible hardware variations of input and output pins related to clock generation unit and functions to access the data. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice.h | 1 + .../net/ethernet/intel/ice/ice_adminq_cmd.h | 240 ++++++++- drivers/net/ethernet/intel/ice/ice_common.c | 467 ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 43 ++ drivers/net/ethernet/intel/ice/ice_lib.c | 17 +- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 411 +++++++++++++++ drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 240 +++++++++ drivers/net/ethernet/intel/ice/ice_type.h | 1 + 8 files changed, 1415 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index b4bca1d964a9..ae58d7499955 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -199,6 +199,7 @@ enum ice_feature { ICE_F_DSCP, ICE_F_PTP_EXTTS, ICE_F_SMA_CTRL, + ICE_F_CGU, ICE_F_GNSS, ICE_F_MAX }; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 63d3e1dcbba5..ffa17bb9a8fb 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1339,6 +1339,32 @@ struct ice_aqc_set_mac_lb { u8 reserved[15]; }; +/* Set PHY recovered clock output (direct 0x0630) */ +struct ice_aqc_set_phy_rec_clk_out { + u8 phy_output; + u8 port_num; +#define ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT 0xFF + u8 flags; +#define ICE_AQC_SET_PHY_REC_CLK_OUT_OUT_EN BIT(0) + u8 rsvd; + __le32 freq; + u8 rsvd2[6]; + __le16 node_handle; +}; + +/* Get PHY recovered clock output (direct 0x0631) */ +struct ice_aqc_get_phy_rec_clk_out { + u8 phy_output; + u8 port_num; +#define ICE_AQC_GET_PHY_REC_CLK_OUT_CURR_PORT 0xFF + u8 flags; +#define ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN BIT(0) + u8 rsvd; + __le32 freq; + u8 rsvd2[6]; + __le16 node_handle; +}; + struct ice_aqc_link_topo_params { u8 lport_num; u8 lport_num_valid; @@ -1355,6 +1381,8 @@ struct ice_aqc_link_topo_params { #define ICE_AQC_LINK_TOPO_NODE_TYPE_CAGE 6 #define ICE_AQC_LINK_TOPO_NODE_TYPE_MEZZ 7 #define ICE_AQC_LINK_TOPO_NODE_TYPE_ID_EEPROM 8 +#define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL 9 +#define ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX 10 #define ICE_AQC_LINK_TOPO_NODE_CTX_S 4 #define ICE_AQC_LINK_TOPO_NODE_CTX_M \ (0xF << ICE_AQC_LINK_TOPO_NODE_CTX_S) @@ -1391,7 +1419,12 @@ struct ice_aqc_link_topo_addr { struct ice_aqc_get_link_topo { struct ice_aqc_link_topo_addr addr; u8 node_part_num; -#define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21 +#define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21 +#define ICE_ACQ_GET_LINK_TOPO_NODE_NR_ZL30632_80032 0x24 +#define ICE_ACQ_GET_LINK_TOPO_NODE_NR_SI5383_5384 0x25 +#define ICE_ACQ_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30 +#define ICE_ACQ_GET_LINK_TOPO_NODE_NR_C827 0x31 +#define ICE_ACQ_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47 u8 rsvd[9]; }; @@ -2079,6 +2112,186 @@ struct ice_aqc_get_pkg_info_resp { struct ice_aqc_get_pkg_info pkg_info[]; }; +/* Get CGU abilities command response data structure (indirect 0x0C61) */ +struct ice_aqc_get_cgu_abilities { + u8 num_inputs; + u8 num_outputs; + u8 pps_dpll_idx; + u8 eec_dpll_idx; + __le32 max_in_freq; + __le32 max_in_phase_adj; + __le32 max_out_freq; + __le32 max_out_phase_adj; + u8 cgu_part_num; + u8 rsvd[3]; +}; + +/* Set CGU input config (direct 0x0C62) */ +struct ice_aqc_set_cgu_input_config { + u8 input_idx; + u8 flags1; +#define ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ BIT(6) +#define ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_DELAY BIT(7) + u8 flags2; +#define ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN BIT(5) +#define ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN BIT(6) + u8 rsvd; + __le32 freq; + __le32 phase_delay; + u8 rsvd2[2]; + __le16 node_handle; +}; + +/* Get CGU input config response descriptor structure (direct 0x0C63) */ +struct ice_aqc_get_cgu_input_config { + u8 input_idx; + u8 status; +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_LOS BIT(0) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_SCM_FAIL BIT(1) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_CFM_FAIL BIT(2) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_GST_FAIL BIT(3) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_PFM_FAIL BIT(4) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_FAIL BIT(6) +#define ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP BIT(7) + u8 type; +#define ICE_AQC_GET_CGU_IN_CFG_TYPE_READ_ONLY BIT(0) +#define ICE_AQC_GET_CGU_IN_CFG_TYPE_GPS BIT(4) +#define ICE_AQC_GET_CGU_IN_CFG_TYPE_EXTERNAL BIT(5) +#define ICE_AQC_GET_CGU_IN_CFG_TYPE_PHY BIT(6) + u8 flags1; +#define ICE_AQC_GET_CGU_IN_CFG_FLG1_PHASE_DELAY_SUPP BIT(0) +#define ICE_AQC_GET_CGU_IN_CFG_FLG1_1PPS_SUPP BIT(2) +#define ICE_AQC_GET_CGU_IN_CFG_FLG1_10MHZ_SUPP BIT(3) +#define ICE_AQC_GET_CGU_IN_CFG_FLG1_ANYFREQ BIT(7) + __le32 freq; + __le32 phase_delay; + u8 flags2; +#define ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN BIT(5) +#define ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN BIT(6) + u8 rsvd[1]; + __le16 node_handle; +}; + +/* Set CGU output config (direct 0x0C64) */ +struct ice_aqc_set_cgu_output_config { + u8 output_idx; + u8 flags; +#define ICE_AQC_SET_CGU_OUT_CFG_OUT_EN BIT(0) +#define ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN BIT(1) +#define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ BIT(2) +#define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_PHASE BIT(3) +#define ICE_AQC_SET_CGU_OUT_CFG_UPDATE_SRC_SEL BIT(4) + u8 src_sel; +#define ICE_AQC_SET_CGU_OUT_CFG_DPLL_SRC_SEL ICE_M(0x1F, 0) + u8 rsvd; + __le32 freq; + __le32 phase_delay; + u8 rsvd2[2]; + __le16 node_handle; +}; + +/* Get CGU output config (direct 0x0C65) */ +struct ice_aqc_get_cgu_output_config { + u8 output_idx; + u8 flags; +#define ICE_AQC_GET_CGU_OUT_CFG_OUT_EN BIT(0) +#define ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN BIT(1) +#define ICE_AQC_GET_CGU_OUT_CFG_ESYNC_ABILITY BIT(2) + u8 src_sel; +#define ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL_SHIFT 0 +#define ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL \ + ICE_M(0x1F, ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL_SHIFT) +#define ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE_SHIFT 5 +#define ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE \ + ICE_M(0x7, ICE_AQC_GET_CGU_OUT_CFG_DPLL_MODE_SHIFT) + u8 rsvd; + __le32 freq; + __le32 src_freq; + u8 rsvd2[2]; + __le16 node_handle; +}; + +/* Get CGU DPLL status (direct 0x0C66) */ +struct ice_aqc_get_cgu_dpll_status { + u8 dpll_num; + u8 ref_state; +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_LOS BIT(0) +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_SCM BIT(1) +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_CFM BIT(2) +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_GST BIT(3) +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_PFM BIT(4) +#define ICE_AQC_GET_CGU_DPLL_STATUS_FAST_LOCK_EN BIT(5) +#define ICE_AQC_GET_CGU_DPLL_STATUS_REF_SW_ESYNC BIT(6) + __le16 dpll_state; +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK BIT(0) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO BIT(1) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY BIT(2) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_FLHIT BIT(5) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_PSLHIT BIT(7) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT 8 +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SEL \ + ICE_M(0x1F, ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT) +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE_SHIFT 13 +#define ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE \ + ICE_M(0x7, ICE_AQC_GET_CGU_DPLL_STATUS_STATE_MODE_SHIFT) + __le32 phase_offset_h; + __le32 phase_offset_l; + u8 eec_mode; +#define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_1 0xA +#define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_2 0xB +#define ICE_AQC_GET_CGU_DPLL_STATUS_EEC_MODE_UNKNOWN 0xF + u8 rsvd[1]; + __le16 node_handle; +}; + +/* Set CGU DPLL config (direct 0x0C67) */ +struct ice_aqc_set_cgu_dpll_config { + u8 dpll_num; + u8 ref_state; +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_LOS BIT(0) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_SCM BIT(1) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_CFM BIT(2) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_GST BIT(3) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_PFM BIT(4) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_FLOCK_EN BIT(5) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_REF_SW_ESYNC BIT(6) + u8 rsvd; + u8 config; +#define ICE_AQC_SET_CGU_DPLL_CONFIG_CLK_REF_SEL ICE_M(0x1F, 0) +#define ICE_AQC_SET_CGU_DPLL_CONFIG_MODE ICE_M(0x7, 5) + u8 rsvd2[8]; + u8 eec_mode; + u8 rsvd3[1]; + __le16 node_handle; +}; + +/* Set CGU reference priority (direct 0x0C68) */ +struct ice_aqc_set_cgu_ref_prio { + u8 dpll_num; + u8 ref_idx; + u8 ref_priority; + u8 rsvd[11]; + __le16 node_handle; +}; + +/* Get CGU reference priority (direct 0x0C69) */ +struct ice_aqc_get_cgu_ref_prio { + u8 dpll_num; + u8 ref_idx; + u8 ref_priority; /* Valid only in response */ + u8 rsvd[13]; +}; + +/* Get CGU info (direct 0x0C6A) */ +struct ice_aqc_get_cgu_info { + __le32 cgu_id; + __le32 cgu_cfg_ver; + __le32 cgu_fw_ver; + u8 node_part_num; + u8 dev_rev; + __le16 node_handle; +}; + /* Driver Shared Parameters (direct, 0x0C90) */ struct ice_aqc_driver_shared_params { u8 set_or_get_op; @@ -2148,6 +2361,8 @@ struct ice_aq_desc { struct ice_aqc_get_phy_caps get_phy; struct ice_aqc_set_phy_cfg set_phy; struct ice_aqc_restart_an restart_an; + struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out; + struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out; struct ice_aqc_gpio read_write_gpio; struct ice_aqc_sff_eeprom read_write_sff_param; struct ice_aqc_set_port_id_led set_port_id_led; @@ -2187,6 +2402,15 @@ struct ice_aq_desc { struct ice_aqc_fw_logging fw_logging; struct ice_aqc_get_clear_fw_log get_clear_fw_log; struct ice_aqc_download_pkg download_pkg; + struct ice_aqc_set_cgu_input_config set_cgu_input_config; + struct ice_aqc_get_cgu_input_config get_cgu_input_config; + struct ice_aqc_set_cgu_output_config set_cgu_output_config; + struct ice_aqc_get_cgu_output_config get_cgu_output_config; + struct ice_aqc_get_cgu_dpll_status get_cgu_dpll_status; + struct ice_aqc_set_cgu_dpll_config set_cgu_dpll_config; + struct ice_aqc_set_cgu_ref_prio set_cgu_ref_prio; + struct ice_aqc_get_cgu_ref_prio get_cgu_ref_prio; + struct ice_aqc_get_cgu_info get_cgu_info; struct ice_aqc_driver_shared_params drv_shared_params; struct ice_aqc_set_mac_lb set_mac_lb; struct ice_aqc_alloc_free_res_cmd sw_res_ctrl; @@ -2310,6 +2534,8 @@ enum ice_adminq_opc { ice_aqc_opc_get_link_status = 0x0607, ice_aqc_opc_set_event_mask = 0x0613, ice_aqc_opc_set_mac_lb = 0x0620, + ice_aqc_opc_set_phy_rec_clk_out = 0x0630, + ice_aqc_opc_get_phy_rec_clk_out = 0x0631, ice_aqc_opc_get_link_topo = 0x06E0, ice_aqc_opc_read_i2c = 0x06E2, ice_aqc_opc_write_i2c = 0x06E3, @@ -2364,6 +2590,18 @@ enum ice_adminq_opc { ice_aqc_opc_update_pkg = 0x0C42, ice_aqc_opc_get_pkg_info_list = 0x0C43, + /* 1588/SyncE commands/events */ + ice_aqc_opc_get_cgu_abilities = 0x0C61, + ice_aqc_opc_set_cgu_input_config = 0x0C62, + ice_aqc_opc_get_cgu_input_config = 0x0C63, + ice_aqc_opc_set_cgu_output_config = 0x0C64, + ice_aqc_opc_get_cgu_output_config = 0x0C65, + ice_aqc_opc_get_cgu_dpll_status = 0x0C66, + ice_aqc_opc_set_cgu_dpll_config = 0x0C67, + ice_aqc_opc_set_cgu_ref_prio = 0x0C68, + ice_aqc_opc_get_cgu_ref_prio = 0x0C69, + ice_aqc_opc_get_cgu_info = 0x0C6A, + ice_aqc_opc_driver_shared_params = 0x0C90, /* Standalone Commands/Events */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 0157f6e98d3e..35e00133575c 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -434,6 +434,83 @@ ice_aq_get_link_topo_handle(struct ice_port_info *pi, u8 node_type, return ice_aq_send_cmd(pi->hw, &desc, NULL, 0, cd); } +/** + * ice_aq_get_netlist_node + * @hw: pointer to the hw struct + * @cmd: get_link_topo AQ structure + * @node_part_number: output node part number if node found + * @node_handle: output node handle parameter if node found + * + * Get netlist node handle. + */ +int +ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, + u8 *node_part_number, u16 *node_handle) +{ + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); + desc.params.get_link_topo = *cmd; + + if (ice_aq_send_cmd(hw, &desc, NULL, 0, NULL)) + return -EINTR; + + if (node_handle) + *node_handle = + le16_to_cpu(desc.params.get_link_topo.addr.handle); + if (node_part_number) + *node_part_number = desc.params.get_link_topo.node_part_num; + + return 0; +} + +#define MAX_NETLIST_SIZE 10 + +/** + * ice_find_netlist_node + * @hw: pointer to the hw struct + * @node_type_ctx: type of netlist node to look for + * @node_part_number: node part number to look for + * @node_handle: output parameter if node found - optional + * + * Find and return the node handle for a given node type and part number in the + * netlist. When found ICE_SUCCESS is returned, ICE_ERR_DOES_NOT_EXIST + * otherwise. If node_handle provided, it would be set to found node handle. + */ +int +ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, u8 node_part_number, + u16 *node_handle) +{ + struct ice_aqc_get_link_topo cmd; + u8 rec_node_part_number; + u16 rec_node_handle; + u8 idx; + + for (idx = 0; idx < MAX_NETLIST_SIZE; idx++) { + int status; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.addr.topo_params.node_type_ctx = + (node_type_ctx << ICE_AQC_LINK_TOPO_NODE_TYPE_S); + cmd.addr.topo_params.index = idx; + + status = ice_aq_get_netlist_node(hw, &cmd, + &rec_node_part_number, + &rec_node_handle); + if (status) + return status; + + if (rec_node_part_number == node_part_number) { + if (node_handle) + *node_handle = rec_node_handle; + return 0; + } + } + + return -ENOTBLK; +} + /** * ice_is_media_cage_present * @pi: port information structure @@ -4917,6 +4994,396 @@ ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid, return status; } +/** + * ice_aq_get_cgu_abilities + * @hw: pointer to the HW struct + * @abilities: CGU abilities + * + * Get CGU abilities (0x0C61) + */ +int +ice_aq_get_cgu_abilities(struct ice_hw *hw, + struct ice_aqc_get_cgu_abilities *abilities) +{ + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_abilities); + return ice_aq_send_cmd(hw, &desc, abilities, sizeof(*abilities), NULL); +} + +/** + * ice_aq_set_input_pin_cfg + * @hw: pointer to the HW struct + * @input_idx: Input index + * @flags1: Input flags + * @flags2: Input flags + * @freq: Frequency in Hz + * @phase_delay: Delay in ps + * + * Set CGU input config (0x0C62) + */ +int +ice_aq_set_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 flags1, u8 flags2, + u32 freq, s32 phase_delay) +{ + struct ice_aqc_set_cgu_input_config *cmd; + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_input_config); + cmd = &desc.params.set_cgu_input_config; + cmd->input_idx = input_idx; + cmd->flags1 = flags1; + cmd->flags2 = flags2; + cmd->freq = cpu_to_le32(freq); + cmd->phase_delay = cpu_to_le32(phase_delay); + + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); +} + +/** + * ice_aq_get_input_pin_cfg + * @hw: pointer to the HW struct + * @input_idx: Input index + * @status: Pin status + * @type: Pin type + * @flags1: Input flags + * @flags2: Input flags + * @freq: Frequency in Hz + * @phase_delay: Delay in ps + * + * Get CGU input config (0x0C63) + */ +int +ice_aq_get_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 *status, u8 *type, + u8 *flags1, u8 *flags2, u32 *freq, s32 *phase_delay) +{ + struct ice_aqc_get_cgu_input_config *cmd; + struct ice_aq_desc desc; + int ret; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_input_config); + cmd = &desc.params.get_cgu_input_config; + cmd->input_idx = input_idx; + + ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!ret) { + if (status) + *status = cmd->status; + if (type) + *type = cmd->type; + if (flags1) + *flags1 = cmd->flags1; + if (flags2) + *flags2 = cmd->flags2; + if (freq) + *freq = le32_to_cpu(cmd->freq); + if (phase_delay) + *phase_delay = le32_to_cpu(cmd->phase_delay); + } + + return ret; +} + +/** + * ice_aq_set_output_pin_cfg + * @hw: pointer to the HW struct + * @output_idx: Output index + * @flags: Output flags + * @src_sel: Index of DPLL block + * @freq: Output frequency + * @phase_delay: Output phase compensation + * + * Set CGU output config (0x0C64) + */ +int +ice_aq_set_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 flags, + u8 src_sel, u32 freq, s32 phase_delay) +{ + struct ice_aqc_set_cgu_output_config *cmd; + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_output_config); + cmd = &desc.params.set_cgu_output_config; + cmd->output_idx = output_idx; + cmd->flags = flags; + cmd->src_sel = src_sel; + cmd->freq = cpu_to_le32(freq); + cmd->phase_delay = cpu_to_le32(phase_delay); + + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); +} + +/** + * ice_aq_get_output_pin_cfg + * @hw: pointer to the HW struct + * @output_idx: Output index + * @flags: Output flags + * @src_sel: Internal DPLL source + * @freq: Output frequency + * @src_freq: Source frequency + * + * Get CGU output config (0x0C65) + */ +int +ice_aq_get_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 *flags, + u8 *src_sel, u32 *freq, u32 *src_freq) +{ + struct ice_aqc_get_cgu_output_config *cmd; + struct ice_aq_desc desc; + int ret; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_output_config); + cmd = &desc.params.get_cgu_output_config; + cmd->output_idx = output_idx; + + ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!ret) { + if (flags) + *flags = cmd->flags; + if (src_sel) + *src_sel = cmd->src_sel; + if (freq) + *freq = le32_to_cpu(cmd->freq); + if (src_freq) + *src_freq = le32_to_cpu(cmd->src_freq); + } + + return ret; +} + +/** + * convert_s48_to_s64 - convert 48 bit value to 64 bit value + * @signed_48: signed 64 bit variable storing signed 48 bit value + * + * Convert signed 48 bit value to its 64 bit representation. + * + * Return: signed 64 bit representation of signed 48 bit value. + */ +static inline +s64 convert_s48_to_s64(s64 signed_48) +{ + const s64 MASK_SIGN_BITS = GENMASK_ULL(63, 48); + const s64 SIGN_BIT_47 = BIT_ULL(47); + + return ((signed_48 & SIGN_BIT_47) ? (s64)(MASK_SIGN_BITS | signed_48) + : signed_48); +} + +/** + * ice_aq_get_cgu_dpll_status + * @hw: pointer to the HW struct + * @dpll_num: DPLL index + * @ref_state: Reference clock state + * @dpll_state: DPLL state + * @phase_offset: Phase offset in ns + * @eec_mode: EEC_mode + * + * Get CGU DPLL status (0x0C66) + */ +int +ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state, + u16 *dpll_state, s64 *phase_offset, u8 *eec_mode) +{ + struct ice_aqc_get_cgu_dpll_status *cmd; + const s64 NSEC_PER_PSEC = 1000LL; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_dpll_status); + cmd = &desc.params.get_cgu_dpll_status; + cmd->dpll_num = dpll_num; + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) { + *ref_state = cmd->ref_state; + *dpll_state = le16_to_cpu(cmd->dpll_state); + *phase_offset = le32_to_cpu(cmd->phase_offset_h); + *phase_offset <<= 32; + *phase_offset += le32_to_cpu(cmd->phase_offset_l); + *phase_offset = convert_s48_to_s64(*phase_offset) + / NSEC_PER_PSEC; + *eec_mode = cmd->eec_mode; + } + + return status; +} + +/** + * ice_aq_set_cgu_dpll_config + * @hw: pointer to the HW struct + * @dpll_num: DPLL index + * @ref_state: Reference clock state + * @config: DPLL config + * @eec_mode: EEC mode + * + * Set CGU DPLL config (0x0C67) + */ +int +ice_aq_set_cgu_dpll_config(struct ice_hw *hw, u8 dpll_num, u8 ref_state, + u8 config, u8 eec_mode) +{ + struct ice_aqc_set_cgu_dpll_config *cmd; + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_dpll_config); + cmd = &desc.params.set_cgu_dpll_config; + cmd->dpll_num = dpll_num; + cmd->ref_state = ref_state; + cmd->config = config; + cmd->eec_mode = eec_mode; + + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); +} + +/** + * ice_aq_set_cgu_ref_prio + * @hw: pointer to the HW struct + * @dpll_num: DPLL index + * @ref_idx: Reference pin index + * @ref_priority: Reference input priority + * + * Set CGU reference priority (0x0C68) + */ +int +ice_aq_set_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, + u8 ref_priority) +{ + struct ice_aqc_set_cgu_ref_prio *cmd; + struct ice_aq_desc desc; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_cgu_ref_prio); + cmd = &desc.params.set_cgu_ref_prio; + cmd->dpll_num = dpll_num; + cmd->ref_idx = ref_idx; + cmd->ref_priority = ref_priority; + + return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); +} + +/** + * ice_aq_get_cgu_ref_prio + * @hw: pointer to the HW struct + * @dpll_num: DPLL index + * @ref_idx: Reference pin index + * @ref_prio: Reference input priority + * + * Get CGU reference priority (0x0C69) + */ +int +ice_aq_get_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, + u8 *ref_prio) +{ + struct ice_aqc_get_cgu_ref_prio *cmd; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_ref_prio); + cmd = &desc.params.get_cgu_ref_prio; + cmd->dpll_num = dpll_num; + cmd->ref_idx = ref_idx; + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) + *ref_prio = cmd->ref_priority; + + return status; +} + +/** + * ice_aq_get_cgu_info + * @hw: pointer to the HW struct + * @cgu_id: CGU ID + * @cgu_cfg_ver: CGU config version + * @cgu_fw_ver: CGU firmware version + * + * Get CGU info (0x0C6A) + */ +int +ice_aq_get_cgu_info(struct ice_hw *hw, u32 *cgu_id, u32 *cgu_cfg_ver, + u32 *cgu_fw_ver) +{ + struct ice_aqc_get_cgu_info *cmd; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cgu_info); + cmd = &desc.params.get_cgu_info; + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) { + *cgu_id = le32_to_cpu(cmd->cgu_id); + *cgu_cfg_ver = le32_to_cpu(cmd->cgu_cfg_ver); + *cgu_fw_ver = le32_to_cpu(cmd->cgu_fw_ver); + } + + return status; +} + +/** + * ice_aq_set_phy_rec_clk_out - set RCLK phy out + * @hw: pointer to the HW struct + * @phy_output: PHY reference clock output pin + * @enable: GPIO state to be applied + * @freq: PHY output frequency + * + * Set CGU reference priority (0x0630) + * Return 0 on success or negative value on failure. + */ +int +ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, + u32 *freq) +{ + struct ice_aqc_set_phy_rec_clk_out *cmd; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_rec_clk_out); + cmd = &desc.params.set_phy_rec_clk_out; + cmd->phy_output = phy_output; + cmd->port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; + cmd->flags = enable & ICE_AQC_SET_PHY_REC_CLK_OUT_OUT_EN; + cmd->freq = cpu_to_le32(*freq); + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) + *freq = le32_to_cpu(cmd->freq); + + return status; +} + +/** + * ice_aq_get_phy_rec_clk_out + * @hw: pointer to the HW struct + * @phy_output: PHY reference clock output pin + * @port_num: Port number + * @flags: PHY flags + * @freq: PHY output frequency + * + * Get PHY recovered clock output (0x0631) + */ +int +ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, u8 *port_num, + u8 *flags, u32 *freq) +{ + struct ice_aqc_get_phy_rec_clk_out *cmd; + struct ice_aq_desc desc; + int status; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_phy_rec_clk_out); + cmd = &desc.params.get_phy_rec_clk_out; + cmd->phy_output = phy_output; + cmd->port_num = *port_num; + + status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); + if (!status) { + *port_num = cmd->port_num; + *flags = cmd->flags; + *freq = le32_to_cpu(cmd->freq); + } + + return status; +} + /** * ice_replay_pre_init - replay pre initialization * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 8ba5f935a092..99c933552cc2 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -94,6 +94,12 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, struct ice_aqc_get_phy_caps_data *caps, struct ice_sq_cd *cd); int +ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, u8 node_part_number, + u16 *node_handle); +int +ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, + u8 *node_part_number, u16 *node_handle); +int ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, enum ice_adminq_opc opc, struct ice_sq_cd *cd); int @@ -192,6 +198,43 @@ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); struct ice_q_ctx * ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle); int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in); +int +ice_aq_get_cgu_abilities(struct ice_hw *hw, + struct ice_aqc_get_cgu_abilities *abilities); +int +ice_aq_set_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 flags1, u8 flags2, + u32 freq, s32 phase_delay); +int +ice_aq_get_input_pin_cfg(struct ice_hw *hw, u8 input_idx, u8 *status, u8 *type, + u8 *flags1, u8 *flags2, u32 *freq, s32 *phase_delay); +int +ice_aq_set_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 flags, + u8 src_sel, u32 freq, s32 phase_delay); +int +ice_aq_get_output_pin_cfg(struct ice_hw *hw, u8 output_idx, u8 *flags, + u8 *src_sel, u32 *freq, u32 *src_freq); +int +ice_aq_get_cgu_dpll_status(struct ice_hw *hw, u8 dpll_num, u8 *ref_state, + u16 *dpll_state, s64 *phase_offset, u8 *eec_mode); +int +ice_aq_set_cgu_dpll_config(struct ice_hw *hw, u8 dpll_num, u8 ref_state, + u8 config, u8 eec_mode); +int +ice_aq_set_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, + u8 ref_priority); +int +ice_aq_get_cgu_ref_prio(struct ice_hw *hw, u8 dpll_num, u8 ref_idx, + u8 *ref_prio); +int +ice_aq_get_cgu_info(struct ice_hw *hw, u32 *cgu_id, u32 *cgu_cfg_ver, + u32 *cgu_fw_ver); + +int +ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable, + u32 *freq); +int +ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, u8 *port_num, + u8 *flags, u32 *freq); void ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 5ddb95d1073a..3ff9907b1e80 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -4044,13 +4044,22 @@ void ice_init_feature_support(struct ice_pf *pf) case ICE_DEV_ID_E810C_BACKPLANE: case ICE_DEV_ID_E810C_QSFP: case ICE_DEV_ID_E810C_SFP: + case ICE_DEV_ID_E810_XXV_BACKPLANE: + case ICE_DEV_ID_E810_XXV_QSFP: + case ICE_DEV_ID_E810_XXV_SFP: ice_set_feature_support(pf, ICE_F_DSCP); ice_set_feature_support(pf, ICE_F_PTP_EXTTS); - if (ice_is_e810t(&pf->hw)) { + if (ice_is_phy_rclk_present(&pf->hw)) + ice_set_feature_support(pf, ICE_F_PHY_RCLK); + /* If we don't own the timer - don't enable other caps */ + if (!pf->hw.func_caps.ts_func_info.src_tmr_owned) + break; + if (ice_is_cgu_present(&pf->hw)) + ice_set_feature_support(pf, ICE_F_CGU); + if (ice_is_clock_mux_present_e810t(&pf->hw)) ice_set_feature_support(pf, ICE_F_SMA_CTRL); - if (ice_gnss_is_gps_present(&pf->hw)) - ice_set_feature_support(pf, ICE_F_GNSS); - } + if (ice_gnss_is_gps_present(&pf->hw)) + ice_set_feature_support(pf, ICE_F_GNSS); break; default: break; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index a38614d21ea8..e9a371fa038b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -3213,6 +3213,91 @@ ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) return 0; } +/** + * ice_is_phy_rclk_present + * @hw: pointer to the hw struct + * + * Check if the PHY Recovered Clock device is present in the netlist + * Return: + * * true - device found in netlist + * * false - device not found + */ +bool ice_is_phy_rclk_present(struct ice_hw *hw) +{ + if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_ACQ_GET_LINK_TOPO_NODE_NR_C827, NULL) && + ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_ACQ_GET_LINK_TOPO_NODE_NR_E822_PHY, NULL)) + return false; + + return true; +} + +/** + * ice_is_clock_mux_present_e810t + * @hw: pointer to the hw struct + * + * Check if the Clock Multiplexer device is present in the netlist + * Return: + * * true - device found in netlist + * * false - device not found + */ +bool ice_is_clock_mux_present_e810t(struct ice_hw *hw) +{ + if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX, + ICE_ACQ_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX, + NULL)) + return false; + + return true; +} + +/** + * ice_get_pf_c827_idx - find and return the C827 index for the current pf + * @hw: pointer to the hw struct + * @idx: index of the found C827 PHY + * Return: + * * 0 - success + * * negative - failure + */ +int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx) +{ + struct ice_aqc_get_link_topo cmd; + u8 node_part_number; + u16 node_handle; + int status; + u8 ctx; + + if (hw->mac_type != ICE_MAC_E810) + return -ENODEV; + + if (hw->device_id != ICE_DEV_ID_E810C_QSFP) { + *idx = C827_0; + return 0; + } + + memset(&cmd, 0, sizeof(cmd)); + + ctx = ICE_AQC_LINK_TOPO_NODE_TYPE_PHY << ICE_AQC_LINK_TOPO_NODE_TYPE_S; + ctx |= ICE_AQC_LINK_TOPO_NODE_CTX_PORT << ICE_AQC_LINK_TOPO_NODE_CTX_S; + cmd.addr.topo_params.node_type_ctx = ctx; + cmd.addr.topo_params.index = 0; + + status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number, + &node_handle); + if (status || node_part_number != ICE_ACQ_GET_LINK_TOPO_NODE_NR_C827) + return -ENOENT; + + if (node_handle == E810C_QSFP_C827_0_HANDLE) + *idx = C827_0; + else if (node_handle == E810C_QSFP_C827_1_HANDLE) + *idx = C827_1; + else + return -EIO; + + return 0; +} + /** * ice_read_sma_ctrl_e810t * @hw: pointer to the hw struct @@ -3381,3 +3466,329 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) return ice_get_phy_tx_tstamp_ready_e822(hw, block, tstamp_ready); } + +/** + * ice_is_cgu_present + * @hw: pointer to the hw struct + * + * Check if the Clock Generation Unit (CGU) device is present in the netlist + * Return: + * * true - cgu is present + * * false - cgu is not present + */ +bool ice_is_cgu_present(struct ice_hw *hw) +{ + if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_ACQ_GET_LINK_TOPO_NODE_NR_ZL30632_80032, + NULL)) { + hw->cgu_part_number = ICE_ACQ_GET_LINK_TOPO_NODE_NR_ZL30632_80032; + return true; + } else if (!ice_find_netlist_node(hw, + ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_ACQ_GET_LINK_TOPO_NODE_NR_SI5383_5384, + NULL)) { + hw->cgu_part_number = ICE_ACQ_GET_LINK_TOPO_NODE_NR_SI5383_5384; + return true; + } + + return false; +} + +/** + * ice_cgu_get_pin_desc_e823 + * @hw: pointer to the hw struct + * @input: if request is done against input or output pin + * @size: number of inputs/outputs + * + * Return: pointer to pin description array associated to given hw. + */ +static const struct ice_cgu_pin_desc * +ice_cgu_get_pin_desc_e823(struct ice_hw *hw, bool input, int *size) +{ + static const struct ice_cgu_pin_desc *t; + + if (hw->cgu_part_number == + ICE_ACQ_GET_LINK_TOPO_NODE_NR_ZL30632_80032) { + if (input) { + t = ice_e823_zl_cgu_inputs; + *size = ARRAY_SIZE(ice_e823_zl_cgu_inputs); + } else { + t = ice_e823_zl_cgu_outputs; + *size = ARRAY_SIZE(ice_e823_zl_cgu_outputs); + } + } else if (hw->cgu_part_number == + ICE_ACQ_GET_LINK_TOPO_NODE_NR_SI5383_5384) { + if (input) { + t = ice_e823_si_cgu_inputs; + *size = ARRAY_SIZE(ice_e823_si_cgu_inputs); + } else { + t = ice_e823_si_cgu_outputs; + *size = ARRAY_SIZE(ice_e823_si_cgu_outputs); + } + } else { + t = NULL; + *size = 0; + } + + return t; +} + +/** + * ice_cgu_get_pin_desc + * @hw: pointer to the hw struct + * @input: if request is done against input or output pins + * @size: size of array returned by function + * + * Return: pointer to pin description array associated to given hw. + */ +static const struct ice_cgu_pin_desc * +ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size) +{ + const struct ice_cgu_pin_desc *t = NULL; + + switch (hw->device_id) { + case ICE_DEV_ID_E810C_SFP: + if (input) { + t = ice_e810t_sfp_cgu_inputs; + *size = ARRAY_SIZE(ice_e810t_sfp_cgu_inputs); + } else { + t = ice_e810t_sfp_cgu_outputs; + *size = ARRAY_SIZE(ice_e810t_sfp_cgu_outputs); + } + break; + case ICE_DEV_ID_E810C_QSFP: + if (input) { + t = ice_e810t_qsfp_cgu_inputs; + *size = ARRAY_SIZE(ice_e810t_qsfp_cgu_inputs); + } else { + t = ice_e810t_qsfp_cgu_outputs; + *size = ARRAY_SIZE(ice_e810t_qsfp_cgu_outputs); + } + break; + case ICE_DEV_ID_E823L_10G_BASE_T: + case ICE_DEV_ID_E823L_1GBE: + case ICE_DEV_ID_E823L_BACKPLANE: + case ICE_DEV_ID_E823L_QSFP: + case ICE_DEV_ID_E823L_SFP: + case ICE_DEV_ID_E823C_10G_BASE_T: + case ICE_DEV_ID_E823C_BACKPLANE: + case ICE_DEV_ID_E823C_QSFP: + case ICE_DEV_ID_E823C_SFP: + case ICE_DEV_ID_E823C_SGMII: + t = ice_cgu_get_pin_desc_e823(hw, input, size); + break; + default: + break; + } + + return t; +} + +/** + * ice_cgu_get_pin_type + * @hw: pointer to the hw struct + * @pin: pin index + * @input: if request is done against input or output pin + * + * Return: type of a pin. + */ +enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input) +{ + const struct ice_cgu_pin_desc *t; + int t_size; + + t = ice_cgu_get_pin_desc(hw, input, &t_size); + + if (!t) + return 0; + + if (pin >= t_size) + return 0; + + return t[pin].type; +} + +/** + * ice_cgu_get_pin_sig_type_mask + * @hw: pointer to the hw struct + * @pin: pin index + * @input: if request is done against input or output pin + * + * Return: signal type bit mask of a pin. + */ +unsigned long +ice_cgu_get_pin_freq_mask(struct ice_hw *hw, u8 pin, bool input) +{ + const struct ice_cgu_pin_desc *t; + int t_size; + + t = ice_cgu_get_pin_desc(hw, input, &t_size); + + if (!t) + return 0; + + if (pin >= t_size) + return 0; + + return t[pin].sig_type_mask; +} + +/** + * ice_cgu_get_pin_name + * @hw: pointer to the hw struct + * @pin: pin index + * @input: if request is done against input or output pin + * + * Return: + * * null terminated char array with name + * * NULL in case of failure + */ +const char *ice_cgu_get_pin_name(struct ice_hw *hw, u8 pin, bool input) +{ + const struct ice_cgu_pin_desc *t; + int t_size; + + t = ice_cgu_get_pin_desc(hw, input, &t_size); + + if (!t) + return NULL; + + if (pin >= t_size) + return NULL; + + return t[pin].name; +} + +/** + * ice_get_cgu_state - get the state of the DPLL + * @hw: pointer to the hw struct + * @dpll_idx: Index of internal DPLL unit + * @last_dpll_state: last known state of DPLL + * @pin: pointer to a buffer for returning currently active pin + * @ref_state: reference clock state + * @phase_offset: pointer to a buffer for returning phase offset + * @dpll_state: state of the DPLL (output) + * + * This function will read the state of the DPLL(dpll_idx). Non-null + * 'pin', 'ref_state', 'eec_mode' and 'phase_offset' parameters are used to + * retrieve currently active pin, state, mode and phase_offset respectively. + * + * Return: state of the DPLL + */ +int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx, + enum ice_cgu_state last_dpll_state, u8 *pin, + u8 *ref_state, u8 *eec_mode, s64 *phase_offset, + enum ice_cgu_state *dpll_state) +{ + u8 hw_ref_state, hw_eec_mode; + s64 hw_phase_offset; + u16 hw_dpll_state; + int status; + + status = ice_aq_get_cgu_dpll_status(hw, dpll_idx, &hw_ref_state, + &hw_dpll_state, &hw_phase_offset, + &hw_eec_mode); + if (status) { + *dpll_state = ICE_CGU_STATE_INVALID; + return status; + } + + if (pin) { + /* current ref pin in dpll_state_refsel_status_X register */ + *pin = (hw_dpll_state & + ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SEL) >> + ICE_AQC_GET_CGU_DPLL_STATUS_STATE_CLK_REF_SHIFT; + } + + if (phase_offset) + *phase_offset = hw_phase_offset; + + if (ref_state) + *ref_state = hw_ref_state; + + if (eec_mode) + *eec_mode = hw_eec_mode; + + if (!dpll_state) + return status; + + /* According to ZL DPLL documentation, once state reach LOCKED_HO_ACQ + * it would never return to FREERUN. This aligns to ITU-T G.781 + * Recommendation. We cannot report HOLDOVER as HO memory is cleared + * while switching to another reference. + * Only for situations where previous state was either: "LOCKED without + * HO_ACQ" or "HOLDOVER" we actually back to FREERUN. + */ + if (hw_dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_LOCK) { + if (hw_dpll_state & ICE_AQC_GET_CGU_DPLL_STATUS_STATE_HO_READY) + *dpll_state = ICE_CGU_STATE_LOCKED_HO_ACQ; + else + *dpll_state = ICE_CGU_STATE_LOCKED; + } else if (last_dpll_state == ICE_CGU_STATE_LOCKED_HO_ACQ || + last_dpll_state == ICE_CGU_STATE_HOLDOVER) { + *dpll_state = ICE_CGU_STATE_HOLDOVER; + } else { + *dpll_state = ICE_CGU_STATE_FREERUN; + } + + return status; +} + +/** + * ice_get_cgu_rclk_pin_info - get info on available recovered clock pins + * @hw: pointer to the hw struct + * @base_idx: returns index of first recovered clock pin on device + * @pin_num: returns number of recovered clock pins available on device + * + * Based on hw provide caller info about recovery clock pins available on the + * board. + * + * Return: + * * 0 - success, information is valid + * * negative - failure, information is not valid + */ +int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num) +{ + u8 phy_idx; + int ret; + + switch (hw->device_id) { + case ICE_DEV_ID_E810C_SFP: + case ICE_DEV_ID_E810C_QSFP: + + ret = ice_get_pf_c827_idx(hw, &phy_idx); + if (ret) + return ret; + *base_idx = E810T_CGU_INPUT_C827(phy_idx, ICE_RCLKA_PIN); + *pin_num = ICE_E810_RCLK_PINS_NUM; + ret = 0; + break; + case ICE_DEV_ID_E823L_10G_BASE_T: + case ICE_DEV_ID_E823L_1GBE: + case ICE_DEV_ID_E823L_BACKPLANE: + case ICE_DEV_ID_E823L_QSFP: + case ICE_DEV_ID_E823L_SFP: + case ICE_DEV_ID_E823C_10G_BASE_T: + case ICE_DEV_ID_E823C_BACKPLANE: + case ICE_DEV_ID_E823C_QSFP: + case ICE_DEV_ID_E823C_SFP: + case ICE_DEV_ID_E823C_SGMII: + *pin_num = ICE_E822_RCLK_PINS_NUM; + ret = 0; + if (hw->cgu_part_number == + ICE_ACQ_GET_LINK_TOPO_NODE_NR_ZL30632_80032) + *base_idx = ZL_REF1P; + else if (hw->cgu_part_number == + ICE_ACQ_GET_LINK_TOPO_NODE_NR_SI5383_5384) + *base_idx = SI_REF1P; + else + ret = -ENODEV; + + break; + default: + ret = -ENODEV; + break; + } + + return ret; +} diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 3b68cb91bd81..d09e5bca0ff1 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -3,6 +3,7 @@ #ifndef _ICE_PTP_HW_H_ #define _ICE_PTP_HW_H_ +#include enum ice_ptp_tmr_cmd { INIT_TIME, @@ -109,6 +110,232 @@ struct ice_cgu_pll_params_e822 { u32 post_pll_div; }; +#define E810C_QSFP_C827_0_HANDLE 2 +#define E810C_QSFP_C827_1_HANDLE 3 +enum ice_e810_c827_idx { + C827_0, + C827_1 +}; + +enum ice_phy_rclk_pins { + ICE_RCLKA_PIN = 0, /* SCL pin */ + ICE_RCLKB_PIN, /* SDA pin */ +}; + +#define ICE_E810_RCLK_PINS_NUM (ICE_RCLKB_PIN + 1) +#define ICE_E822_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1) +#define E810T_CGU_INPUT_C827(_phy, _pin) ((_phy) * ICE_E810_RCLK_PINS_NUM + \ + (_pin) + ZL_REF1P) +enum ice_cgu_state { + ICE_CGU_STATE_UNKNOWN = -1, + ICE_CGU_STATE_INVALID, /* state is not valid */ + ICE_CGU_STATE_FREERUN, /* clock is free-running */ + ICE_CGU_STATE_LOCKED, /* clock is locked to the reference, + * but the holdover memory is not valid + */ + ICE_CGU_STATE_LOCKED_HO_ACQ, /* clock is locked to the reference + * and holdover memory is valid + */ + ICE_CGU_STATE_HOLDOVER, /* clock is in holdover mode */ + ICE_CGU_STATE_MAX +}; + +#define MAX_CGU_STATE_NAME_LEN 14 +struct ice_cgu_state_desc { + char name[MAX_CGU_STATE_NAME_LEN]; + enum ice_cgu_state state; +}; + +enum ice_zl_cgu_in_pins { + ZL_REF0P = 0, + ZL_REF0N, + ZL_REF1P, + ZL_REF1N, + ZL_REF2P, + ZL_REF2N, + ZL_REF3P, + ZL_REF3N, + ZL_REF4P, + ZL_REF4N, + NUM_ZL_CGU_INPUT_PINS +}; + +enum ice_zl_cgu_out_pins { + ZL_OUT0 = 0, + ZL_OUT1, + ZL_OUT2, + ZL_OUT3, + ZL_OUT4, + ZL_OUT5, + ZL_OUT6, + NUM_ZL_CGU_OUTPUT_PINS +}; + +enum ice_si_cgu_in_pins { + SI_REF0P = 0, + SI_REF0N, + SI_REF1P, + SI_REF1N, + SI_REF2P, + SI_REF2N, + SI_REF3, + SI_REF4, + NUM_SI_CGU_INPUT_PINS +}; + +enum ice_si_cgu_out_pins { + SI_OUT0 = 0, + SI_OUT1, + SI_OUT2, + SI_OUT3, + SI_OUT4, + NUM_SI_CGU_OUTPUT_PINS +}; + +#define MAX_CGU_PIN_NAME_LEN 16 +#define ICE_SIG_TYPE_MASK_1PPS_10MHZ (BIT(DPLL_PIN_FREQ_SUPP_1_HZ) | \ + BIT(DPLL_PIN_FREQ_SUPP_10_MHZ)) +struct ice_cgu_pin_desc { + char name[MAX_CGU_PIN_NAME_LEN]; + u8 index; + enum dpll_pin_type type; + unsigned long sig_type_mask; +}; + +static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = { + { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, + BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, +}; + +static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = { + { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "C827_1-RCLKA", ZL_REF2P, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "C827_1-RCLKB", ZL_REF2N, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, + BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, +}; + +static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_outputs[] = { + { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "MAC-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "CVL-SDP21", ZL_OUT4, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "CVL-SDP23", ZL_OUT5, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, +}; + +static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_outputs[] = { + { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "PHY2-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "MAC-CLK", ZL_OUT4, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "CVL-SDP21", ZL_OUT5, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "CVL-SDP23", ZL_OUT6, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, +}; + +static const struct ice_cgu_pin_desc ice_e823_si_cgu_inputs[] = { + { "NONE", SI_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", SI_REF0N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "SYNCE0_DP", SI_REF1P, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "SYNCE0_DN", SI_REF1N, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "EXT_CLK_SYNC", SI_REF2P, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "NONE", SI_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "EXT_PPS_OUT", SI_REF3, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "INT_PPS_OUT", SI_REF4, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, +}; + +static const struct ice_cgu_pin_desc ice_e823_si_cgu_outputs[] = { + { "1588-TIME_SYNC", SI_OUT0, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "PHY-CLK", SI_OUT1, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "10MHZ-SMA2", SI_OUT2, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "PPS-SMA1", SI_OUT3, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, +}; + +static const struct ice_cgu_pin_desc ice_e823_zl_cgu_inputs[] = { + { "NONE", ZL_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "INT_PPS_OUT", ZL_REF0N, DPLL_PIN_TYPE_EXT, + BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + { "SYNCE0_DP", ZL_REF1P, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "SYNCE0_DN", ZL_REF1N, DPLL_PIN_TYPE_MUX, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "NONE", ZL_REF2P, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", ZL_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "EXT_CLK_SYNC", ZL_REF3P, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "NONE", ZL_REF3N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "EXT_PPS_OUT", ZL_REF4P, DPLL_PIN_TYPE_EXT, + BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, +}; + +static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { + { "PPS-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, + BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + { "10MHZ-SMA2", ZL_OUT1, DPLL_PIN_TYPE_EXT, + BIT(DPLL_PIN_FREQ_SUPP_10_MHZ) }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "1588-TIME_REF", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, + BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "CPK-TIME_SYNC", ZL_OUT4, DPLL_PIN_TYPE_EXT, + ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + { "NONE", ZL_OUT5, DPLL_PIN_TYPE_UNSPEC, 0 }, +}; + extern const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ]; @@ -197,6 +424,19 @@ int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data); int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data); int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data); bool ice_is_pca9575_present(struct ice_hw *hw); +bool ice_is_phy_rclk_present(struct ice_hw *hw); +bool ice_is_clock_mux_present_e810t(struct ice_hw *hw); +int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx); +bool ice_is_cgu_present(struct ice_hw *hw); +enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input); +unsigned long +ice_cgu_get_pin_freq_mask(struct ice_hw *hw, u8 pin, bool input); +const char *ice_cgu_get_pin_name(struct ice_hw *hw, u8 pin, bool input); +int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx, + enum ice_cgu_state last_dpll_state, u8 *pin, + u8 *ref_state, u8 *eec_mode, s64 *phase_offset, + enum ice_cgu_state *dpll_state); +int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num); #define PFTSYN_SEM_BYTES 4 diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index a09556e57803..128bc4d326f9 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -963,6 +963,7 @@ struct ice_hw { DECLARE_BITMAP(hw_ptype, ICE_FLOW_PTYPE_MAX); u8 dvm_ena; u16 io_expander_handle; + u8 cgu_part_number; }; /* Statistics collected by each port, VSI, VEB, and S-channel */ From 49a7b540dbc965b6092e38216e04d34d18c9370b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 3 Aug 2022 13:41:14 +0200 Subject: [PATCH 05/93] ice: implement dpll interface to control cgu Control over clock generation unit is required for further development of Synchronous Ethernet feature. Interface provides ability to obtain current state of a dpll, its sources and outputs which are pins, and allows their configuration. Co-developed-by: Milena Olech Signed-off-by: Milena Olech Co-developed-by: Michal Michalik Signed-off-by: Michal Michalik Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/Kconfig | 1 + drivers/net/ethernet/intel/ice/Makefile | 3 +- drivers/net/ethernet/intel/ice/ice.h | 4 + drivers/net/ethernet/intel/ice/ice_dpll.c | 1929 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_dpll.h | 101 + drivers/net/ethernet/intel/ice/ice_main.c | 7 + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 21 +- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 148 +- 8 files changed, 2125 insertions(+), 89 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_dpll.c create mode 100644 drivers/net/ethernet/intel/ice/ice_dpll.h diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 9bc0a9519899..913dcf928d15 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -284,6 +284,7 @@ config ICE select DIMLIB select NET_DEVLINK select PLDMFW + select DPLL help This driver supports Intel(R) Ethernet Connection E800 Series of devices. For more information on how to identify your adapter, go diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 817977e3039d..85d6366d1f5b 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -34,7 +34,8 @@ ice-y := ice_main.o \ ice_lag.o \ ice_ethtool.o \ ice_repr.o \ - ice_tc_lib.o + ice_tc_lib.o \ + ice_dpll.o ice-$(CONFIG_PCI_IOV) += \ ice_sriov.o \ ice_virtchnl.o \ diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index ae58d7499955..8a110272a799 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -76,6 +76,7 @@ #include "ice_vsi_vlan_ops.h" #include "ice_gnss.h" #include "ice_irq.h" +#include "ice_dpll.h" #define ICE_BAR0 0 #define ICE_REQ_DESC_MULTIPLE 32 @@ -198,6 +199,7 @@ enum ice_feature { ICE_F_DSCP, ICE_F_PTP_EXTTS, + ICE_F_PHY_RCLK, ICE_F_SMA_CTRL, ICE_F_CGU, ICE_F_GNSS, @@ -506,6 +508,7 @@ enum ice_pf_flags { ICE_FLAG_UNPLUG_AUX_DEV, ICE_FLAG_MTU_CHANGED, ICE_FLAG_GNSS, /* GNSS successfully initialized */ + ICE_FLAG_DPLL, /* SyncE/PTP dplls initialized */ ICE_PF_FLAGS_NBITS /* must be last */ }; @@ -628,6 +631,7 @@ struct ice_pf { #define ICE_VF_AGG_NODE_ID_START 65 #define ICE_MAX_VF_AGG_NODES 32 struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES]; + struct ice_dplls dplls; }; struct ice_netdev_priv { diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c new file mode 100644 index 000000000000..3217fb36dd12 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -0,0 +1,1929 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022, Intel Corporation. */ + +#include "ice.h" +#include "ice_lib.h" +#include "ice_trace.h" +#include +#include + +#define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 +#define ICE_DPLL_LOCK_TRIES 1000 +#define ICE_DPLL_PIN_IDX_INVALID 0xff + +/** + * dpll_lock_status - map ice cgu states into dpll's subsystem lock status + */ +static const enum dpll_lock_status +ice_dpll_status[__DPLL_LOCK_STATUS_MAX] = { + [ICE_CGU_STATE_INVALID] = DPLL_LOCK_STATUS_UNSPEC, + [ICE_CGU_STATE_FREERUN] = DPLL_LOCK_STATUS_UNLOCKED, + [ICE_CGU_STATE_LOCKED] = DPLL_LOCK_STATUS_CALIBRATING, + [ICE_CGU_STATE_LOCKED_HO_ACQ] = DPLL_LOCK_STATUS_LOCKED, + [ICE_CGU_STATE_HOLDOVER] = DPLL_LOCK_STATUS_HOLDOVER, +}; + +/** + * ice_dpll_pin_type - enumerate ice pin types + */ +enum ice_dpll_pin_type { + ICE_DPLL_PIN_INVALID = 0, + ICE_DPLL_PIN_TYPE_SOURCE, + ICE_DPLL_PIN_TYPE_OUTPUT, + ICE_DPLL_PIN_TYPE_RCLK_SOURCE, +}; + +/** + * pin_type_name - string names of ice pin types + */ +static const char * const pin_type_name[] = { + [ICE_DPLL_PIN_TYPE_SOURCE] = "source", + [ICE_DPLL_PIN_TYPE_OUTPUT] = "output", + [ICE_DPLL_PIN_TYPE_RCLK_SOURCE] = "rclk-source", +}; + +/** + * ice_find_pin_idx - find ice_dpll_pin index on a pf + * @pf: private board structure + * @pin: kernel's dpll_pin pointer to be searched for + * @pin_type: type of pins to be searched for + * + * Find and return internal ice pin index of a searched dpll subsystem + * pin pointer. + * + * Return: + * * valid index for a given pin & pin type found on pf internal dpll struct + * * ICE_DPLL_PIN_IDX_INVALID - if pin was not found. + */ +static u32 +ice_find_pin_idx(struct ice_pf *pf, const struct dpll_pin *pin, + enum ice_dpll_pin_type pin_type) + +{ + struct ice_dpll_pin *pins; + int pin_num, i; + + if (!pin || !pf) + return ICE_DPLL_PIN_IDX_INVALID; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + pins = pf->dplls.inputs; + pin_num = pf->dplls.num_inputs; + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + pins = pf->dplls.outputs; + pin_num = pf->dplls.num_outputs; + } else { + return ICE_DPLL_PIN_IDX_INVALID; + } + + for (i = 0; i < pin_num; i++) + if (pin == pins[i].pin) + return i; + + return ICE_DPLL_PIN_IDX_INVALID; +} + +/** + * ice_dpll_cb_lock - lock dplls mutex in callback context + * @pf: private board structure + * + * Lock the mutex from the callback operations invoked by dpll subsystem. + * Prevent dead lock caused by `rmmod ice` when dpll callbacks are under stress + * tests. + * + * Return: + * 0 - if lock acquired + * negative - lock not acquired or dpll was deinitialized + */ +static int ice_dpll_cb_lock(struct ice_pf *pf) +{ + int i; + + for (i = 0; i < ICE_DPLL_LOCK_TRIES; i++) { + if (mutex_trylock(&pf->dplls.lock)) + return 0; + usleep_range(100, 150); + if (!test_bit(ICE_FLAG_DPLL, pf->flags)) + return -EFAULT; + } + + return -EBUSY; +} + +/** + * ice_dpll_cb_unlock - unlock dplls mutex in callback context + * @pf: private board structure + * + * Unlock the mutex from the callback operations invoked by dpll subsystem. + */ +static void ice_dpll_cb_unlock(struct ice_pf *pf) +{ + mutex_unlock(&pf->dplls.lock); +} + +/** + * ice_find_pin - find ice_dpll_pin on a pf + * @pf: private board structure + * @pin: kernel's dpll_pin pointer to be searched for + * @pin_type: type of pins to be searched for + * + * Find and return internal ice pin info pointer holding data of given dpll + * subsystem pin pointer. + * + * Return: + * * valid 'struct ice_dpll_pin'-type pointer - if given 'pin' pointer was + * found in pf internal pin data. + * * NULL - if pin was not found. + */ +static struct ice_dpll_pin +*ice_find_pin(struct ice_pf *pf, const struct dpll_pin *pin, + enum ice_dpll_pin_type pin_type) + +{ + struct ice_dpll_pin *pins; + int pin_num, i; + + if (!pin || !pf) + return NULL; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + pins = pf->dplls.inputs; + pin_num = pf->dplls.num_inputs; + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + pins = pf->dplls.outputs; + pin_num = pf->dplls.num_outputs; + } else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) { + if (pin == pf->dplls.rclk.pin) + return &pf->dplls.rclk; + } else { + return NULL; + } + + for (i = 0; i < pin_num; i++) + if (pin == pins[i].pin) + return &pins[i]; + + return NULL; +} + +/** + * ice_dpll_pin_freq_set - set pin's frequency + * @pf: private board structure + * @pin: pointer to a pin + * @pin_type: type of pin being configured + * @freq: frequency to be set + * + * Set requested frequency on a pin. + * + * Return: + * * 0 - success + * * negative - error on AQ or wrong pin type given + */ +static int +ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, + const enum ice_dpll_pin_type pin_type, const u32 freq) +{ + u8 flags; + int ret; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + flags = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ; + ret = ice_aq_set_input_pin_cfg(&pf->hw, pin->idx, flags, + pin->flags[0], freq, 0); + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + flags = pin->flags[0] | ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ; + ret = ice_aq_set_output_pin_cfg(&pf->hw, pin->idx, flags, + 0, freq, 0); + } else { + ret = -EINVAL; + } + + if (ret) { + dev_dbg(ice_pf_to_dev(pf), + "err:%d %s failed to set pin freq:%u on pin:%u\n", + ret, ice_aq_str(pf->hw.adminq.sq_last_status), + freq, pin->idx); + } else { + pin->freq = freq; + } + + return ret; +} + +/** + * ice_dpll_frequency_set - wrapper for pin callback for set frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @frequency: frequency to be set + * @extack: error reporting + * @pin_type: type of pin being configured + * + * Wraps internal set frequency command on a pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't set in hw + */ +static int +ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + const u32 frequency, + struct netlink_ext_ack *extack, + const enum ice_dpll_pin_type pin_type) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, pin_type); + if (!p) { + NL_SET_ERR_MSG(extack, "pin not found"); + goto unlock; + } + + ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency); + if (ret) + NL_SET_ERR_MSG_FMT(extack, "freq not set, err:%d", ret); +unlock: + ice_dpll_cb_unlock(pf); + + return ret; +} + +/** + * ice_dpll_source_frequency_set - source pin callback for set frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: frequency to be set + * @extack: error reporting + * + * Wraps internal set frequency command on a pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't set in hw + */ +static int +ice_dpll_source_frequency_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 frequency, struct netlink_ext_ack *extack) +{ + return ice_dpll_frequency_set(pin, pin_priv, dpll, (u32)frequency, extack, + ICE_DPLL_PIN_TYPE_SOURCE); +} + +/** + * ice_dpll_output_frequency_set - output pin callback for set frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: frequency to be set + * @extack: error reporting + * + * Wraps internal set frequency command on a pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't set in hw + */ +static int +ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 frequency, struct netlink_ext_ack *extack) +{ + return ice_dpll_frequency_set(pin, pin_priv, dpll, frequency, extack, + ICE_DPLL_PIN_TYPE_OUTPUT); +} + +/** + * ice_dpll_frequency_get - wrapper for pin callback for get frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: on success holds pin's frequency + * @extack: error reporting + * @pin_type: type of pin being configured + * + * Wraps internal get frequency command of a pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't get from hw + */ +static int +ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, u64 *frequency, + struct netlink_ext_ack *extack, + const enum ice_dpll_pin_type pin_type) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, pin_type); + if (!p) { + NL_SET_ERR_MSG(extack, "pin not found"); + goto unlock; + } + *frequency = (u64)(p->freq); + ret = 0; +unlock: + ice_dpll_cb_unlock(pf); + + return ret; +} + +/** + * ice_dpll_source_frequency_get - source pin callback for get frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: on success holds pin's frequency + * @extack: error reporting + * + * Wraps internal get frequency command of a source pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't get from hw + */ +static int +ice_dpll_source_frequency_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack) +{ + return ice_dpll_frequency_get(pin, pin_priv, dpll, frequency, extack, + ICE_DPLL_PIN_TYPE_SOURCE); +} + +/** + * ice_dpll_output_frequency_get - output pin callback for get frequency + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration + * @frequency: on success holds pin's frequency + * @extack: error reporting + * + * Wraps internal get frequency command of a pin. + * + * Return: + * * 0 - success + * * negative - error pin not found or couldn't get from hw + */ +static int +ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack) +{ + return ice_dpll_frequency_get(pin, pin_priv, dpll, frequency, extack, + ICE_DPLL_PIN_TYPE_OUTPUT); +} + +/** + * ice_dpll_pin_enable - enable a pin on dplls + * @hw: board private hw structure + * @pin: pointer to a pin + * @pin_type: type of pin being enabled + * + * Enable a pin on both dplls. Store current state in pin->flags. + * + * Return: + * * 0 - OK + * * negative - error + */ +static int +ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, + const enum ice_dpll_pin_type pin_type) +{ + u8 flags = pin->flags[0]; + int ret; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + flags |= ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN; + ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; + ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); + } + if (ret) + dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), + "err:%d %s failed to enable %s pin:%u\n", + ret, ice_aq_str(hw->adminq.sq_last_status), + pin_type_name[pin_type], pin->idx); + else + pin->flags[0] = flags; + + return ret; +} + +/** + * ice_dpll_pin_disable - disable a pin on dplls + * @hw: board private hw structure + * @pin: pointer to a pin + * @pin_type: type of pin being disabled + * + * Disable a pin on both dplls. Store current state in pin->flags. + * + * Return: + * * 0 - OK + * * negative - error + */ +static int +ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, + enum ice_dpll_pin_type pin_type) +{ + u8 flags = pin->flags[0]; + int ret; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + flags &= ~(ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN); + ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + flags &= ~(ICE_AQC_SET_CGU_OUT_CFG_OUT_EN); + ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); + } + if (ret) + dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), + "err:%d %s failed to disable %s pin:%u\n", + ret, ice_aq_str(hw->adminq.sq_last_status), + pin_type_name[pin_type], pin->idx); + else + pin->flags[0] = flags; + + return ret; +} + +/** + * ice_dpll_pin_state_update - update pin's state + * @hw: private board struct + * @pin: structure with pin attributes to be updated + * @pin_type: type of pin being updated + * + * Determine pin current state and frequency, then update struct + * holding the pin info. For source pin states are separated for each + * dpll, for rclk pins states are separated for each parent. + * + * Return: + * * 0 - OK + * * negative - error + */ +int +ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, + const enum ice_dpll_pin_type pin_type) +{ + int ret; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL, + NULL, &pin->flags[0], + &pin->freq, NULL); + if (!!(ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0])) { + if (pin->pin) { + pin->state[pf->dplls.eec.dpll_idx] = + pin->pin == pf->dplls.eec.active_source ? + DPLL_PIN_STATE_CONNECTED : + DPLL_PIN_STATE_SELECTABLE; + pin->state[pf->dplls.pps.dpll_idx] = + pin->pin == pf->dplls.pps.active_source ? + DPLL_PIN_STATE_CONNECTED : + DPLL_PIN_STATE_SELECTABLE; + } else { + pin->state[pf->dplls.eec.dpll_idx] = + DPLL_PIN_STATE_SELECTABLE; + pin->state[pf->dplls.pps.dpll_idx] = + DPLL_PIN_STATE_SELECTABLE; + } + } else { + pin->state[pf->dplls.eec.dpll_idx] = + DPLL_PIN_STATE_DISCONNECTED; + pin->state[pf->dplls.pps.dpll_idx] = + DPLL_PIN_STATE_DISCONNECTED; + } + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx, + &pin->flags[0], NULL, + &pin->freq, NULL); + if (!!(ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0])) + pin->state[0] = DPLL_PIN_STATE_CONNECTED; + else + pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; + } else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) { + u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; + + for (parent = 0; parent < pf->dplls.rclk.num_parents; + parent++) { + ret = ice_aq_get_phy_rec_clk_out(&pf->hw, parent, + &port_num, + &pin->flags[parent], + &pin->freq); + if (ret) + return ret; + if (!!(ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN & + pin->flags[parent])) + pin->state[parent] = DPLL_PIN_STATE_CONNECTED; + else + pin->state[parent] = + DPLL_PIN_STATE_DISCONNECTED; + } + } + + return ret; +} + +/** + * ice_find_dpll - find ice_dpll on a pf + * @pf: private board structure + * @dpll: kernel's dpll_device pointer to be searched + * + * Return: + * * pointer if ice_dpll with given device dpll pointer is found + * * NULL if not found + */ +static struct ice_dpll +*ice_find_dpll(struct ice_pf *pf, const struct dpll_device *dpll) +{ + if (!pf || !dpll) + return NULL; + + return dpll == pf->dplls.eec.dpll ? &pf->dplls.eec : + dpll == pf->dplls.pps.dpll ? &pf->dplls.pps : NULL; +} + +/** + * ice_dpll_hw_source_prio_set - set source priority value in hardware + * @pf: board private structure + * @dpll: ice dpll pointer + * @pin: ice pin pointer + * @prio: priority value being set on a dpll + * + * Internal wrapper for setting the priority in the hardware. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int +ice_dpll_hw_source_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, + struct ice_dpll_pin *pin, const u32 prio) +{ + int ret; + + ret = ice_aq_set_cgu_ref_prio(&pf->hw, dpll->dpll_idx, pin->idx, + (u8)prio); + if (ret) + dev_dbg(ice_pf_to_dev(pf), + "err:%d %s failed to set pin prio:%u on pin:%u\n", + ret, ice_aq_str(pf->hw.adminq.sq_last_status), + prio, pin->idx); + else + dpll->input_prio[pin->idx] = prio; + + return ret; +} + +/** + * ice_dpll_lock_status_get - get dpll lock status callback + * @dpll: registered dpll pointer + * @status: on success holds dpll's lock status + * + * Dpll subsystem callback, provides dpll's lock status. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, + enum dpll_lock_status *status, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = priv; + struct ice_dpll *d; + + if (!pf) + return -EINVAL; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + d = ice_find_dpll(pf, dpll); + if (!d) + return -EFAULT; + dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pf:%p\n", __func__, dpll, pf); + *status = ice_dpll_status[d->dpll_state]; + ice_dpll_cb_unlock(pf); + + return 0; +} + +/** + * ice_dpll_mode_get - get dpll's working mode + * @dpll: registered dpll pointer + * @priv: private data pointer passed on dpll registration + * @mode: on success holds current working mode of dpll + * @extack: error reporting + * + * Dpll subsystem callback. Provides working mode of dpll. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_mode_get(const struct dpll_device *dpll, void *priv, + enum dpll_mode *mode, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = priv; + struct ice_dpll *d; + + if (!pf) + return -EINVAL; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + d = ice_find_dpll(pf, dpll); + ice_dpll_cb_unlock(pf); + if (!d) + return -EFAULT; + *mode = DPLL_MODE_AUTOMATIC; + + return 0; +} + +/** + * ice_dpll_mode_get - check if dpll's working mode is supported + * @dpll: registered dpll pointer + * @priv: private data pointer passed on dpll registration + * @mode: mode to be checked for support + * @extack: error reporting + * + * Dpll subsystem callback. Provides information if working mode is supported + * by dpll. + * + * Return: + * * true - mode is supported + * * false - mode is not supported + */ +static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, + const enum dpll_mode mode, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = priv; + struct ice_dpll *d; + + if (!pf) + return false; + + if (ice_dpll_cb_lock(pf)) + return false; + d = ice_find_dpll(pf, dpll); + ice_dpll_cb_unlock(pf); + if (!d) + return false; + if (mode == DPLL_MODE_AUTOMATIC) + return true; + + return false; +} + +/** + * ice_dpll_pin_state_set - set pin's state on dpll + * @dpll: dpll being configured + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @state: state of pin to be set + * @extack: error reporting + * @pin_type: type of a pin + * + * Set pin state on a pin. + * + * Return: + * * 0 - OK or no change required + * * negative - error + */ +static int +ice_dpll_pin_state_set(const struct dpll_device *dpll, + const struct dpll_pin *pin, void *pin_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack, + const enum ice_dpll_pin_type pin_type) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, pin_type); + if (!p) + goto unlock; + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + if (state == DPLL_PIN_STATE_SELECTABLE) + ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); + else if (state == DPLL_PIN_STATE_DISCONNECTED) + ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + if (state == DPLL_PIN_STATE_CONNECTED) + ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); + else if (state == DPLL_PIN_STATE_DISCONNECTED) + ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); + } + if (!ret) + ret = ice_dpll_pin_state_update(pf, p, pin_type); +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), + "%s: dpll:%p, pin:%p, p:%p pf:%p state: %d ret:%d\n", + __func__, dpll, pin, p, pf, state, ret); + + return ret; +} + +/** + * ice_dpll_output_state_set - enable/disable output pin on dpll device + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: dpll being configured + * @dpll_priv: private data pointer passed on dpll registration + * @state: state of pin to be set + * @extack: error reporting + * + * Dpll subsystem callback. Set given state on output type pin. + * + * Return: + * * 0 - successfully enabled mode + * * negative - failed to enable mode + */ +static int ice_dpll_output_state_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + return ice_dpll_pin_state_set(dpll, pin, pin_priv, state, extack, + ICE_DPLL_PIN_TYPE_OUTPUT); +} + +/** + * ice_dpll_source_state_set - enable/disable source pin on dpll levice + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: dpll being configured + * @dpll_priv: private data pointer passed on dpll registration + * @state: state of pin to be set + * @extack: error reporting + * + * Dpll subsystem callback. Enables given mode on source type pin. + * + * Return: + * * 0 - successfully enabled mode + * * negative - failed to enable mode + */ +static int ice_dpll_source_state_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + return ice_dpll_pin_state_set(dpll, pin, pin_priv, state, extack, + ICE_DPLL_PIN_TYPE_SOURCE); +} + +/** + * ice_dpll_pin_state_get - set pin's state on dpll + * @dpll: registered dpll pointer + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @state: on success holds state of the pin + * @extack: error reporting + * @pin_type: type of questioned pin + * + * Determine pin state set it on a pin. + * + * Return: + * * 0 - success + * * negative - failed to get state + */ +static int +ice_dpll_pin_state_get(const struct dpll_device *dpll, + const struct dpll_pin *pin, void *pin_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack, + const enum ice_dpll_pin_type pin_type) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll_pin *p; + struct ice_dpll *d; + int ret = -EINVAL; + + if (!pf) + return ret; + + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, pin_type); + if (!p) { + NL_SET_ERR_MSG(extack, "pin not found"); + goto unlock; + } + d = ice_find_dpll(pf, dpll); + if (!d) + goto unlock; + ret = ice_dpll_pin_state_update(pf, p, pin_type); + if (ret) + goto unlock; + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) + *state = p->state[d->dpll_idx]; + else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) + *state = p->state[0]; + ret = 0; +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), + "%s: dpll:%p, pin:%p, pf:%p state: %d ret:%d\n", + __func__, dpll, pin, pf, *state, ret); + + return ret; +} + +/** + * ice_dpll_output_state_get - get output pin state on dpll device + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: on success holds state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Check state of a pin. + * + * Return: + * * 0 - success + * * negative - failed to get state + */ +static int ice_dpll_output_state_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + return ice_dpll_pin_state_get(dpll, pin, pin_priv, state, extack, + ICE_DPLL_PIN_TYPE_OUTPUT); +} + +/** + * ice_dpll_source_state_get - get source pin state on dpll device + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @state: on success holds state of the pin + * @extack: error reporting + * + * Dpll subsystem callback. Check state of a source pin. + * + * Return: + * * 0 - success + * * negative - failed to get state + */ +static int ice_dpll_source_state_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + return ice_dpll_pin_state_get(dpll, pin, pin_priv, state, extack, + ICE_DPLL_PIN_TYPE_SOURCE); +} + +/** + * ice_dpll_source_prio_get - get dpll's source prio + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @prio: on success - returns source priority on dpll + * @extack: error reporting + * + * Dpll subsystem callback. Handler for getting priority of a source pin. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u32 *prio, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll *d = NULL; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); + if (!p) { + NL_SET_ERR_MSG(extack, "pin not found"); + goto unlock; + } + d = ice_find_dpll(pf, dpll); + if (!d) { + NL_SET_ERR_MSG(extack, "dpll not found"); + goto unlock; + } + *prio = d->input_prio[p->idx]; + ret = 0; +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, pf:%p ret:%d\n", + __func__, dpll, pin, pf, ret); + + return ret; +} + +/** + * ice_dpll_source_prio_set - set dpll source prio + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @prio: source priority to be set on dpll + * @extack: error reporting + * + * Dpll subsystem callback. Handler for setting priority of a source pin. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u32 prio, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = pin_priv; + struct ice_dpll *d = NULL; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + + if (prio > ICE_DPLL_PRIO_MAX) { + NL_SET_ERR_MSG(extack, "prio out of range"); + return ret; + } + + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); + if (!p) { + NL_SET_ERR_MSG(extack, "pin not found"); + goto unlock; + } + d = ice_find_dpll(pf, dpll); + if (!d) { + NL_SET_ERR_MSG(extack, "dpll not found"); + goto unlock; + } + ret = ice_dpll_hw_source_prio_set(pf, d, p, prio); + if (ret) + NL_SET_ERR_MSG_FMT(extack, "unable to set prio: %d", ret); +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, pf:%p ret:%d\n", + __func__, dpll, pin, pf, ret); + + return ret; +} + +/** + * ice_dpll_source_direction - callback for get source pin direction + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @direction: holds source pin direction + * @extack: error reporting + * + * Dpll subsystem callback. Handler for getting direction of a source pin. + * + * Return: + * * 0 - success + */ +static int ice_dpll_source_direction(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + *direction = DPLL_PIN_DIRECTION_SOURCE; + + return 0; +} + +/** + * ice_dpll_source_direction - callback for get output pin direction + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration + * @direction: holds output pin direction + * @extack: error reporting + * + * Dpll subsystem callback. Handler for getting direction of an output pin. + * + * Return: + * * 0 - success + */ +static int ice_dpll_output_direction(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + *direction = DPLL_PIN_DIRECTION_OUTPUT; + + return 0; +} + +/** + * ice_dpll_rclk_state_on_pin_set - set a state on rclk pin + * @dpll: registered dpll pointer + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @parent_pin: pin parent pointer + * @state: state to be set on pin + * @extack: error reporting + * + * Dpll subsystem callback, set a state of a rclk pin on a parent pin + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_pin *parent_pin, + const enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; + u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; + struct ice_pf *pf = pin_priv; + struct ice_dpll_pin *p; + int ret = -EINVAL; + + if (!pf) + return ret; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + if (!p) { + ret = -EFAULT; + goto unlock; + } + parent_idx = ice_find_pin_idx(pf, parent_pin, + ICE_DPLL_PIN_TYPE_SOURCE); + if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) { + ret = -EFAULT; + goto unlock; + } + for (i = 0; i < pf->dplls.rclk.num_parents; i++) + if (pf->dplls.rclk.parent_idx[i] == parent_idx) + hw_idx = i; + if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) + goto unlock; + + if ((enable && !!(p->flags[hw_idx] & + ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN)) || + (!enable && !(p->flags[hw_idx] & + ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN))) { + ret = -EINVAL; + goto unlock; + } + ret = ice_aq_set_phy_rec_clk_out(&pf->hw, hw_idx, enable, + &p->freq); +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p ret:%d\n", + __func__, parent_pin, pin, pf, ret); + + return ret; +} + +/** + * ice_dpll_rclk_state_on_pin_get - get a state of rclk pin + * @pin: pointer to a pin + * @pin_priv: private data pointer passed on pin registration + * @parent_pin: pin parent pointer + * @state: on success holds pin state on parent pin + * @extack: error reporting + * + * dpll subsystem callback, get a state of a recovered clock pin. + * + * Return: + * * 0 - success + * * negative - failure + */ +static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_pin *parent_pin, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + struct ice_pf *pf = pin_priv; + u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; + struct ice_dpll_pin *p; + int ret = -EFAULT; + + if (!pf) + return ret; + if (ice_dpll_cb_lock(pf)) + return -EBUSY; + p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + if (!p) + goto unlock; + parent_idx = ice_find_pin_idx(pf, parent_pin, + ICE_DPLL_PIN_TYPE_SOURCE); + if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) + goto unlock; + for (i = 0; i < pf->dplls.rclk.num_parents; i++) + if (pf->dplls.rclk.parent_idx[i] == parent_idx) + hw_idx = i; + if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) + goto unlock; + + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + if (ret) + goto unlock; + + if (!!(p->flags[hw_idx] & + ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN)) + *state = DPLL_PIN_STATE_CONNECTED; + else + *state = DPLL_PIN_STATE_DISCONNECTED; + ret = 0; +unlock: + ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p ret:%d\n", + __func__, parent_pin, pin, pf, ret); + + return ret; +} + +static struct dpll_pin_ops ice_dpll_rclk_ops = { + .state_on_pin_set = ice_dpll_rclk_state_on_pin_set, + .state_on_pin_get = ice_dpll_rclk_state_on_pin_get, + .direction_get = ice_dpll_source_direction, +}; + +static struct dpll_pin_ops ice_dpll_source_ops = { + .frequency_get = ice_dpll_source_frequency_get, + .frequency_set = ice_dpll_source_frequency_set, + .state_on_dpll_get = ice_dpll_source_state_get, + .state_on_dpll_set = ice_dpll_source_state_set, + .prio_get = ice_dpll_source_prio_get, + .prio_set = ice_dpll_source_prio_set, + .direction_get = ice_dpll_source_direction, +}; + +static struct dpll_pin_ops ice_dpll_output_ops = { + .frequency_get = ice_dpll_output_frequency_get, + .frequency_set = ice_dpll_output_frequency_set, + .state_on_dpll_get = ice_dpll_output_state_get, + .state_on_dpll_set = ice_dpll_output_state_set, + .direction_get = ice_dpll_output_direction, +}; + +static struct dpll_device_ops ice_dpll_ops = { + .lock_status_get = ice_dpll_lock_status_get, + .mode_get = ice_dpll_mode_get, + .mode_supported = ice_dpll_mode_supported, +}; + +/** + * ice_dpll_release_info - release memory allocated for pins + * @pf: board private structure + * + * Release memory allocated for pins by ice_dpll_init_info function. + */ +static void ice_dpll_release_info(struct ice_pf *pf) +{ + kfree(pf->dplls.inputs); + pf->dplls.inputs = NULL; + kfree(pf->dplls.outputs); + pf->dplls.outputs = NULL; + kfree(pf->dplls.eec.input_prio); + pf->dplls.eec.input_prio = NULL; + kfree(pf->dplls.pps.input_prio); + pf->dplls.pps.input_prio = NULL; +} + +/** + * ice_dpll_release_rclk_pin - release rclk pin from its parents + * @pf: board private structure + * + * Deregister from parent pins and release resources in dpll subsystem. + */ +static void +ice_dpll_release_rclk_pin(struct ice_pf *pf) +{ + struct ice_dpll_pin *rclk = &pf->dplls.rclk; + struct dpll_pin *parent; + int i; + + for (i = 0; i < rclk->num_parents; i++) { + parent = pf->dplls.inputs[rclk->parent_idx[i]].pin; + if (!parent) + continue; + dpll_pin_on_pin_unregister(parent, rclk->pin, + &ice_dpll_rclk_ops, pf); + } + dpll_pin_put(rclk->pin); + rclk->pin = NULL; +} + +/** + * ice_dpll_release_pins - release pin's from dplls registered in subsystem + * @pf: board private structure + * @dpll_eec: dpll_eec dpll pointer + * @dpll_pps: dpll_pps dpll pointer + * @pins: pointer to pins array + * @count: number of pins + * @ops: callback ops registered with the pins + * @cgu: if cgu is present and controlled by this NIC + * + * Deregister and free pins of a given array of pins from dpll devices + * registered in dpll subsystem. + */ +static void +ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, + struct dpll_device *dpll_pps, struct ice_dpll_pin *pins, + int count, struct dpll_pin_ops *ops, bool cgu) +{ + int i; + + for (i = 0; i < count; i++) { + struct ice_dpll_pin *p = &pins[i]; + + if (p && !IS_ERR_OR_NULL(p->pin)) { + if (cgu && dpll_eec) + dpll_pin_unregister(dpll_eec, p->pin, ops, pf); + if (cgu && dpll_pps) + dpll_pin_unregister(dpll_pps, p->pin, ops, pf); + dpll_pin_put(p->pin); + p->pin = NULL; + } + } +} + +/** + * ice_dpll_register_pins - register pins with a dpll + * @pf: board private structure + * @cgu: if cgu is present and controlled by this NIC + * + * Register source or output pins within given DPLL in a Linux dpll subsystem. + * + * Return: + * * 0 - success + * * negative - error + */ +static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) +{ + struct device *dev = ice_pf_to_dev(pf); + struct ice_dpll_pin *pins; + struct dpll_pin_ops *ops; + u32 rclk_idx; + int ret, i; + + ops = &ice_dpll_source_ops; + pins = pf->dplls.inputs; + for (i = 0; i < pf->dplls.num_inputs; i++) { + pins[i].pin = dpll_pin_get(pf->dplls.clock_id, i, + THIS_MODULE, &pins[i].prop); + if (IS_ERR_OR_NULL(pins[i].pin)) { + pins[i].pin = NULL; + return -ENOMEM; + } + if (cgu) { + ret = dpll_pin_register(pf->dplls.eec.dpll, + pins[i].pin, + ops, pf, NULL); + if (ret) + return ret; + ret = dpll_pin_register(pf->dplls.pps.dpll, + pins[i].pin, + ops, pf, NULL); + if (ret) + return ret; + } + } + if (cgu) { + ops = &ice_dpll_output_ops; + pins = pf->dplls.outputs; + for (i = 0; i < pf->dplls.num_outputs; i++) { + pins[i].pin = dpll_pin_get(pf->dplls.clock_id, + i + pf->dplls.num_inputs, + THIS_MODULE, &pins[i].prop); + if (IS_ERR_OR_NULL(pins[i].pin)) { + pins[i].pin = NULL; + return -ENOMEM; + } + ret = dpll_pin_register(pf->dplls.eec.dpll, pins[i].pin, + ops, pf, NULL); + if (ret) + return ret; + ret = dpll_pin_register(pf->dplls.pps.dpll, pins[i].pin, + ops, pf, NULL); + if (ret) + return ret; + } + } + rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; + pf->dplls.rclk.pin = dpll_pin_get(pf->dplls.clock_id, rclk_idx, + THIS_MODULE, &pf->dplls.rclk.prop); + if (IS_ERR_OR_NULL(pf->dplls.rclk.pin)) { + pf->dplls.rclk.pin = NULL; + return -ENOMEM; + } + ops = &ice_dpll_rclk_ops; + for (i = 0; i < pf->dplls.rclk.num_parents; i++) { + struct dpll_pin *parent = + pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; + + ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, + ops, pf, dev); + if (ret) + return ret; + } + + return 0; +} + +/** + * ice_generate_clock_id - generates unique clock_id for registering dpll. + * @pf: board private structure + * @clock_id: holds generated clock_id + * + * Generates unique (per board) clock_id for allocation and search of dpll + * devices in Linux dpll subsystem. + */ +static void ice_generate_clock_id(struct ice_pf *pf, u64 *clock_id) +{ + *clock_id = pci_get_dsn(pf->pdev); +} + +/** + * ice_dpll_init_dplls + * @pf: board private structure + * @cgu: if cgu is present and controlled by this NIC + * + * Get dplls instances for this board, if cgu is controlled by this NIC, + * register dpll with callbacks ops + * + * Return: + * * 0 - success + * * negative - allocation fails + */ +static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) +{ + struct device *dev = ice_pf_to_dev(pf); + int ret = -ENOMEM; + u64 clock_id; + + ice_generate_clock_id(pf, &clock_id); + pf->dplls.eec.dpll = dpll_device_get(clock_id, pf->dplls.eec.dpll_idx, + THIS_MODULE); + if (!pf->dplls.eec.dpll) { + dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (eec)\n"); + return ret; + } + pf->dplls.pps.dpll = dpll_device_get(clock_id, pf->dplls.pps.dpll_idx, + THIS_MODULE); + if (!pf->dplls.pps.dpll) { + dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (pps)\n"); + goto put_eec; + } + + if (cgu) { + ret = dpll_device_register(pf->dplls.eec.dpll, DPLL_TYPE_EEC, + &ice_dpll_ops, pf, dev); + if (ret) + goto put_pps; + ret = dpll_device_register(pf->dplls.pps.dpll, DPLL_TYPE_PPS, + &ice_dpll_ops, pf, dev); + if (ret) + goto put_pps; + } + + return 0; + +put_pps: + dpll_device_put(pf->dplls.pps.dpll); + pf->dplls.pps.dpll = NULL; +put_eec: + dpll_device_put(pf->dplls.eec.dpll); + pf->dplls.eec.dpll = NULL; + + return ret; +} + +/** + * ice_dpll_update_state - update dpll state + * @pf: pf private structure + * @d: pointer to queried dpll device + * + * Poll current state of dpll from hw and update ice_dpll struct. + * Return: + * * 0 - success + * * negative - AQ failure + */ +static int ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) +{ + struct ice_dpll_pin *p; + int ret; + + ret = ice_get_cgu_state(&pf->hw, d->dpll_idx, d->prev_dpll_state, + &d->source_idx, &d->ref_state, &d->eec_mode, + &d->phase_offset, &d->dpll_state); + + dev_dbg(ice_pf_to_dev(pf), + "update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d\n", + d->dpll_idx, d->prev_source_idx, d->source_idx, + d->dpll_state, d->prev_dpll_state); + if (ret) { + dev_err(ice_pf_to_dev(pf), + "update dpll=%d state failed, ret=%d %s\n", + d->dpll_idx, ret, + ice_aq_str(pf->hw.adminq.sq_last_status)); + return ret; + } + if (init) { + if (d->dpll_state == ICE_CGU_STATE_LOCKED && + d->dpll_state == ICE_CGU_STATE_LOCKED_HO_ACQ) + d->active_source = pf->dplls.inputs[d->source_idx].pin; + p = &pf->dplls.inputs[d->source_idx]; + return ice_dpll_pin_state_update(pf, p, + ICE_DPLL_PIN_TYPE_SOURCE); + } + if (d->dpll_state == ICE_CGU_STATE_HOLDOVER || + d->dpll_state == ICE_CGU_STATE_FREERUN) { + d->active_source = NULL; + p = &pf->dplls.inputs[d->source_idx]; + d->prev_source_idx = ICE_DPLL_PIN_IDX_INVALID; + d->source_idx = ICE_DPLL_PIN_IDX_INVALID; + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); + } else if (d->source_idx != d->prev_source_idx) { + p = &pf->dplls.inputs[d->prev_source_idx]; + ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); + p = &pf->dplls.inputs[d->source_idx]; + d->active_source = p->pin; + ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); + d->prev_source_idx = d->source_idx; + } + + return ret; +} + +/** + * ice_dpll_notify_changes - notify dpll subsystem about changes + * @d: pointer do dpll + * + * Once change detected appropriate event is submitted to the dpll subsystem. + */ +static void ice_dpll_notify_changes(struct ice_dpll *d) +{ + if (d->prev_dpll_state != d->dpll_state) { + d->prev_dpll_state = d->dpll_state; + dpll_device_notify(d->dpll, DPLL_A_LOCK_STATUS); + } + if (d->prev_source != d->active_source) { + d->prev_source = d->active_source; + if (d->active_source) + dpll_pin_notify(d->dpll, d->active_source, + DPLL_A_PIN_STATE); + } +} + +/** + * ice_dpll_periodic_work - DPLLs periodic worker + * @work: pointer to kthread_work structure + * + * DPLLs periodic worker is responsible for polling state of dpll. + */ +static void ice_dpll_periodic_work(struct kthread_work *work) +{ + struct ice_dplls *d = container_of(work, struct ice_dplls, work.work); + struct ice_pf *pf = container_of(d, struct ice_pf, dplls); + struct ice_dpll *de = &pf->dplls.eec; + struct ice_dpll *dp = &pf->dplls.pps; + int ret = 0; + + if (!test_bit(ICE_FLAG_DPLL, pf->flags)) + return; + ret = ice_dpll_cb_lock(pf); + if (ret) { + d->lock_err_num++; + goto resched; + } + ret = ice_dpll_update_state(pf, de, false); + if (!ret) + ret = ice_dpll_update_state(pf, dp, false); + if (ret) { + d->cgu_state_acq_err_num++; + /* stop rescheduling this worker */ + if (d->cgu_state_acq_err_num > + ICE_CGU_STATE_ACQ_ERR_THRESHOLD) { + dev_err(ice_pf_to_dev(pf), + "EEC/PPS DPLLs periodic work disabled\n"); + return; + } + } + ice_dpll_cb_unlock(pf); + ice_dpll_notify_changes(de); + ice_dpll_notify_changes(dp); +resched: + /* Run twice a second or reschedule if update failed */ + kthread_queue_delayed_work(d->kworker, &d->work, + ret ? msecs_to_jiffies(10) : + msecs_to_jiffies(500)); +} + +/** + * ice_dpll_init_worker - Initialize DPLLs periodic worker + * @pf: board private structure + * + * Create and start DPLLs periodic worker. + * + * Return: + * * 0 - success + * * negative - create worker failure + */ +static int ice_dpll_init_worker(struct ice_pf *pf) +{ + struct ice_dplls *d = &pf->dplls; + struct kthread_worker *kworker; + + ice_dpll_update_state(pf, &d->eec, true); + ice_dpll_update_state(pf, &d->pps, true); + kthread_init_delayed_work(&d->work, ice_dpll_periodic_work); + kworker = kthread_create_worker(0, "ice-dplls-%s", + dev_name(ice_pf_to_dev(pf))); + if (IS_ERR(kworker)) + return PTR_ERR(kworker); + d->kworker = kworker; + d->cgu_state_acq_err_num = 0; + kthread_queue_delayed_work(d->kworker, &d->work, 0); + + return 0; +} + +/** + * ice_dpll_release_all - disable support for DPLL and unregister dpll device + * @pf: board private structure + * @cgu: if cgu is controlled by this driver instance + * + * This function handles the cleanup work required from the initialization by + * freeing resources and unregistering the dpll. + * + * Context: Called under pf->dplls.lock + */ +static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) +{ + struct ice_dplls *d = &pf->dplls; + struct ice_dpll *de = &d->eec; + struct ice_dpll *dp = &d->pps; + + mutex_lock(&pf->dplls.lock); + ice_dpll_release_rclk_pin(pf); + ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->inputs, + d->num_inputs, &ice_dpll_source_ops, cgu); + mutex_unlock(&pf->dplls.lock); + if (cgu) { + mutex_lock(&pf->dplls.lock); + ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->outputs, + d->num_outputs, + &ice_dpll_output_ops, cgu); + mutex_unlock(&pf->dplls.lock); + } + ice_dpll_release_info(pf); + if (dp->dpll) { + mutex_lock(&pf->dplls.lock); + if (cgu) + dpll_device_unregister(dp->dpll, &ice_dpll_ops, pf); + dpll_device_put(dp->dpll); + mutex_unlock(&pf->dplls.lock); + dev_dbg(ice_pf_to_dev(pf), "PPS dpll removed\n"); + } + + if (de->dpll) { + mutex_lock(&pf->dplls.lock); + if (cgu) + dpll_device_unregister(de->dpll, &ice_dpll_ops, pf); + dpll_device_put(de->dpll); + mutex_unlock(&pf->dplls.lock); + dev_dbg(ice_pf_to_dev(pf), "EEC dpll removed\n"); + } + + if (cgu) { + mutex_lock(&pf->dplls.lock); + kthread_cancel_delayed_work_sync(&d->work); + if (d->kworker) { + kthread_destroy_worker(d->kworker); + d->kworker = NULL; + dev_dbg(ice_pf_to_dev(pf), "DPLLs worker removed\n"); + } + mutex_unlock(&pf->dplls.lock); + } +} + +/** + * ice_dpll_release - Disable the driver/HW support for DPLLs and unregister + * the dpll device. + * @pf: board private structure + * + * Handles the cleanup work required after dpll initialization, + * freeing resources and unregistering the dpll. + */ +void ice_dpll_release(struct ice_pf *pf) +{ + if (test_bit(ICE_FLAG_DPLL, pf->flags)) { + ice_dpll_release_all(pf, + ice_is_feature_supported(pf, ICE_F_CGU)); + mutex_destroy(&pf->dplls.lock); + clear_bit(ICE_FLAG_DPLL, pf->flags); + } +} + +/** + * ice_dpll_init_direct_pins - initializes source or output pins information + * @pf: board private structure + * @pin_type: type of pins being initialized + * + * Init information about input or output pins, cache them in pins struct. + * + * Return: + * * 0 - success + * * negative - init failure + */ +static int +ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) +{ + struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps; + int num_pins, i, ret = -EINVAL; + struct ice_hw *hw = &pf->hw; + struct ice_dpll_pin *pins; + u8 freq_supp_num; + bool input; + + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + pins = pf->dplls.inputs; + num_pins = pf->dplls.num_inputs; + input = true; + } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + pins = pf->dplls.outputs; + num_pins = pf->dplls.num_outputs; + input = false; + } else { + return -EINVAL; + } + + for (i = 0; i < num_pins; i++) { + pins[i].idx = i; + pins[i].prop.label = ice_cgu_get_pin_name(hw, i, input); + pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input); + if (input) { + ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i, + &de->input_prio[i]); + if (ret) + return ret; + ret = ice_aq_get_cgu_ref_prio(hw, dp->dpll_idx, i, + &dp->input_prio[i]); + if (ret) + return ret; + pins[i].prop.capabilities += + DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE; + } + pins[i].prop.capabilities += DPLL_PIN_CAPS_STATE_CAN_CHANGE; + ret = ice_dpll_pin_state_update(pf, &pins[i], pin_type); + if (ret) + return ret; + pins[i].prop.freq_supported = + ice_cgu_get_pin_freq_supp(hw, i, input, &freq_supp_num); + pins[i].prop.freq_supported_num = freq_supp_num; + } + + return ret; +} + +/** + * ice_dpll_init_rclk_pin - initializes rclk pin information + * @pf: board private structure + * @pin_type: type of pins being initialized + * + * Init information for rclk pin, cache them in pf->dplls.rclk. + * + * Return: + * * 0 - success + * * negative - init failure + */ +static int ice_dpll_init_rclk_pin(struct ice_pf *pf) +{ + struct ice_dpll_pin *pin = &pf->dplls.rclk; + struct device *dev = ice_pf_to_dev(pf); + + pin->prop.label = dev_name(dev); + pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; + pin->prop.capabilities += DPLL_PIN_CAPS_STATE_CAN_CHANGE; + + return ice_dpll_pin_state_update(pf, pin, + ICE_DPLL_PIN_TYPE_RCLK_SOURCE); +} + +/** + * ice_dpll_init_pins - init pins wrapper + * @pf: board private structure + * @pin_type: type of pins being initialized + * + * Wraps functions for pin inti. + * + * Return: + * * 0 - success + * * negative - init failure + */ +static int ice_dpll_init_pins(struct ice_pf *pf, + const enum ice_dpll_pin_type pin_type) +{ + if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) + return ice_dpll_init_direct_pins(pf, pin_type); + else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) + return ice_dpll_init_direct_pins(pf, pin_type); + else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) + return ice_dpll_init_rclk_pin(pf); + else + return -EINVAL; +} + +/** + * ice_dpll_init_info - prepare pf's dpll information structure + * @pf: board private structure + * @cgu: if cgu is present and controlled by this NIC + * + * Acquire (from HW) and set basic dpll information (on pf->dplls struct). + * + * Return: + * * 0 - success + * * negative - error + */ +static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) +{ + struct ice_aqc_get_cgu_abilities abilities; + struct ice_dpll *de = &pf->dplls.eec; + struct ice_dpll *dp = &pf->dplls.pps; + struct ice_dplls *d = &pf->dplls; + struct ice_hw *hw = &pf->hw; + int ret, alloc_size, i; + u8 base_rclk_idx; + + ice_generate_clock_id(pf, &d->clock_id); + ret = ice_aq_get_cgu_abilities(hw, &abilities); + if (ret) { + dev_err(ice_pf_to_dev(pf), + "err:%d %s failed to read cgu abilities\n", + ret, ice_aq_str(hw->adminq.sq_last_status)); + return ret; + } + + de->dpll_idx = abilities.eec_dpll_idx; + dp->dpll_idx = abilities.pps_dpll_idx; + d->num_inputs = abilities.num_inputs; + d->num_outputs = abilities.num_outputs; + + alloc_size = sizeof(*d->inputs) * d->num_inputs; + d->inputs = kzalloc(alloc_size, GFP_KERNEL); + if (!d->inputs) + return -ENOMEM; + + alloc_size = sizeof(*de->input_prio) * d->num_inputs; + de->input_prio = kzalloc(alloc_size, GFP_KERNEL); + if (!de->input_prio) + return -ENOMEM; + + dp->input_prio = kzalloc(alloc_size, GFP_KERNEL); + if (!dp->input_prio) + return -ENOMEM; + + ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_SOURCE); + if (ret) + goto release_info; + + if (cgu) { + alloc_size = sizeof(*d->outputs) * d->num_outputs; + d->outputs = kzalloc(alloc_size, GFP_KERNEL); + if (!d->outputs) + goto release_info; + + ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_OUTPUT); + if (ret) + goto release_info; + } + + ret = ice_get_cgu_rclk_pin_info(&pf->hw, &base_rclk_idx, + &pf->dplls.rclk.num_parents); + if (ret) + return ret; + for (i = 0; i < pf->dplls.rclk.num_parents; i++) + pf->dplls.rclk.parent_idx[i] = base_rclk_idx + i; + ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + if (ret) + return ret; + + dev_dbg(ice_pf_to_dev(pf), + "%s - success, inputs:%u, outputs:%u rclk-parents:%u\n", + __func__, d->num_inputs, d->num_outputs, d->rclk.num_parents); + + return 0; + +release_info: + dev_err(ice_pf_to_dev(pf), + "%s - fail: d->inputs:%p, de->input_prio:%p, dp->input_prio:%p, d->outputs:%p\n", + __func__, d->inputs, de->input_prio, + dp->input_prio, d->outputs); + ice_dpll_release_info(pf); + return ret; +} + +/** + * ice_dpll_init - initialize dplls support + * @pf: board private structure + * + * Set up the device dplls registering them and pins connected within Linux dpll + * subsystem. Allow userpsace to obtain state of DPLL and handling of DPLL + * configuration requests. + * + * Return: + * * 0 - success + * * negative - init failure + */ +int ice_dpll_init(struct ice_pf *pf) +{ + bool cgu_present = ice_is_feature_supported(pf, ICE_F_CGU); + struct ice_dplls *d = &pf->dplls; + int err = 0; + + mutex_init(&d->lock); + mutex_lock(&d->lock); + err = ice_dpll_init_info(pf, cgu_present); + if (err) + goto release; + err = ice_dpll_init_dplls(pf, cgu_present); + if (err) + goto release; + err = ice_dpll_register_pins(pf, cgu_present); + if (err) + goto release; + set_bit(ICE_FLAG_DPLL, pf->flags); + if (cgu_present) { + err = ice_dpll_init_worker(pf); + if (err) + goto release; + } + mutex_unlock(&d->lock); + dev_info(ice_pf_to_dev(pf), "DPLLs init successful\n"); + + return err; + +release: + ice_dpll_release_all(pf, cgu_present); + clear_bit(ICE_FLAG_DPLL, pf->flags); + mutex_unlock(&d->lock); + mutex_destroy(&d->lock); + dev_warn(ice_pf_to_dev(pf), "DPLLs init failure\n"); + + return err; +} diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h new file mode 100644 index 000000000000..aad48b9910b7 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2022, Intel Corporation. */ + +#ifndef _ICE_DPLL_H_ +#define _ICE_DPLL_H_ + +#include "ice.h" + +#define ICE_DPLL_PRIO_MAX 0xF +#define ICE_DPLL_RCLK_NUM_MAX 4 +/** ice_dpll_pin - store info about pins + * @pin: dpll pin structure + * @flags: pin flags returned from HW + * @idx: ice pin private idx + * @state: state of a pin + * @type: type of a pin + * @freq_mask: mask of supported frequencies + * @freq: current frequency of a pin + * @caps: capabilities of a pin + * @name: pin name + */ +struct ice_dpll_pin { + struct dpll_pin *pin; + u8 idx; + u8 num_parents; + u8 parent_idx[ICE_DPLL_RCLK_NUM_MAX]; + u8 flags[ICE_DPLL_RCLK_NUM_MAX]; + u8 state[ICE_DPLL_RCLK_NUM_MAX]; + struct dpll_pin_properties prop; + u32 freq; +}; + +/** ice_dpll - store info required for DPLL control + * @dpll: pointer to dpll dev + * @dpll_idx: index of dpll on the NIC + * @source_idx: source currently selected + * @prev_source_idx: source previously selected + * @ref_state: state of dpll reference signals + * @eec_mode: eec_mode dpll is configured for + * @phase_offset: phase delay of a dpll + * @input_prio: priorities of each input + * @dpll_state: current dpll sync state + * @prev_dpll_state: last dpll sync state + * @active_source: pointer to active source pin + * @prev_source: pointer to previous active source pin + */ +struct ice_dpll { + struct dpll_device *dpll; + int dpll_idx; + u8 source_idx; + u8 prev_source_idx; + u8 ref_state; + u8 eec_mode; + s64 phase_offset; + u8 *input_prio; + enum ice_cgu_state dpll_state; + enum ice_cgu_state prev_dpll_state; + struct dpll_pin *active_source; + struct dpll_pin *prev_source; +}; + +/** ice_dplls - store info required for CCU (clock controlling unit) + * @kworker: periodic worker + * @work: periodic work + * @lock: locks access to configuration of a dpll + * @eec: pointer to EEC dpll dev + * @pps: pointer to PPS dpll dev + * @inputs: input pins pointer + * @outputs: output pins pointer + * @rclk: recovered pins pointer + * @num_inputs: number of input pins available on dpll + * @num_outputs: number of output pins available on dpll + * @num_rclk: number of recovered clock pins available on dpll + * @cgu_state_acq_err_num: number of errors returned during periodic work + */ +struct ice_dplls { + struct kthread_worker *kworker; + struct kthread_delayed_work work; + struct mutex lock; + struct ice_dpll eec; + struct ice_dpll pps; + struct ice_dpll_pin *inputs; + struct ice_dpll_pin *outputs; + struct ice_dpll_pin rclk; + u32 num_inputs; + u32 num_outputs; + int cgu_state_acq_err_num; + int lock_err_num; + u8 base_rclk_idx; + u64 clock_id; +}; + +int ice_dpll_init(struct ice_pf *pf); + +void ice_dpll_release(struct ice_pf *pf); + +int ice_dpll_rclk_init(struct ice_pf *pf); + +void ice_dpll_rclk_release(struct ice_pf *pf); + +#endif diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 62e91512aeab..95aa06a20893 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4595,6 +4595,10 @@ static void ice_init_features(struct ice_pf *pf) if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_init(pf); + if (ice_is_feature_supported(pf, ICE_F_CGU) || + ice_is_feature_supported(pf, ICE_F_PHY_RCLK)) + ice_dpll_init(pf); + /* Note: Flow director init failure is non-fatal to load */ if (ice_init_fdir(pf)) dev_err(dev, "could not initialize flow director\n"); @@ -4621,6 +4625,9 @@ static void ice_deinit_features(struct ice_pf *pf) ice_gnss_exit(pf); if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) ice_ptp_release(pf); + if (ice_is_feature_supported(pf, ICE_F_PHY_RCLK) || + ice_is_feature_supported(pf, ICE_F_CGU)) + ice_dpll_release(pf); } static void ice_init_wakeup(struct ice_pf *pf) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index e9a371fa038b..39b692945f73 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -3609,28 +3609,31 @@ enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input) } /** - * ice_cgu_get_pin_sig_type_mask + * ice_cgu_get_pin_freq_supp * @hw: pointer to the hw struct * @pin: pin index * @input: if request is done against input or output pin + * @num: output number of supported frequencies * - * Return: signal type bit mask of a pin. + * Get frequency supported number and array of supported frequencies. + * + * Return: array of supported frequencies for given pin. */ -unsigned long -ice_cgu_get_pin_freq_mask(struct ice_hw *hw, u8 pin, bool input) +struct dpll_pin_frequency * +ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num) { const struct ice_cgu_pin_desc *t; int t_size; + *num = 0; t = ice_cgu_get_pin_desc(hw, input, &t_size); - if (!t) - return 0; - + return NULL; if (pin >= t_size) - return 0; + return NULL; + *num = t[pin].freq_supp_num; - return t[pin].sig_type_mask; + return t[pin].freq_supp; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index d09e5bca0ff1..4568b0403cd7 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -192,147 +192,137 @@ enum ice_si_cgu_out_pins { NUM_SI_CGU_OUTPUT_PINS }; -#define MAX_CGU_PIN_NAME_LEN 16 -#define ICE_SIG_TYPE_MASK_1PPS_10MHZ (BIT(DPLL_PIN_FREQ_SUPP_1_HZ) | \ - BIT(DPLL_PIN_FREQ_SUPP_10_MHZ)) +static struct dpll_pin_frequency ice_cgu_pin_freq_common[] = { + DPLL_PIN_FREQUENCY_1PPS, + DPLL_PIN_FREQUENCY_10MHZ, +}; + +static struct dpll_pin_frequency ice_cgu_pin_freq_1_hz[] = { + DPLL_PIN_FREQUENCY_1PPS, +}; + +static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = { + DPLL_PIN_FREQUENCY_10MHZ, +}; + struct ice_cgu_pin_desc { - char name[MAX_CGU_PIN_NAME_LEN]; + char *name; u8 index; enum dpll_pin_type type; - unsigned long sig_type_mask; + u32 freq_supp_num; + struct dpll_pin_frequency *freq_supp; }; static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = { { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, - { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, 0, }, + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, 0, }, { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, - BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, - { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0, }, }; static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = { { "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "CVL-SDP20", ZL_REF0N, DPLL_PIN_TYPE_INT_OSCILLATOR, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, - { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "C827_1-RCLKA", ZL_REF2P, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "C827_1-RCLKB", ZL_REF2N, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, + { "C827_0-RCLKA", ZL_REF1P, DPLL_PIN_TYPE_MUX, }, + { "C827_0-RCLKB", ZL_REF1N, DPLL_PIN_TYPE_MUX, }, + { "C827_1-RCLKA", ZL_REF2P, DPLL_PIN_TYPE_MUX, }, + { "C827_1-RCLKB", ZL_REF2N, DPLL_PIN_TYPE_MUX, }, { "SMA1", ZL_REF3P, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "SMA2/U.FL2", ZL_REF3N, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS, - BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, - { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, }, }; static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_outputs[] = { { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, - { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "MAC-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, }, + { "MAC-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, }, { "CVL-SDP21", ZL_OUT4, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, { "CVL-SDP23", ZL_OUT5, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, }; static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_outputs[] = { { "REF-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "REF-SMA2/U.FL2", ZL_OUT1, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, - { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "PHY2-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "MAC-CLK", ZL_OUT4, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, + { "PHY2-CLK", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, + { "MAC-CLK", ZL_OUT4, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, { "CVL-SDP21", ZL_OUT5, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, { "CVL-SDP23", ZL_OUT6, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, }; static const struct ice_cgu_pin_desc ice_e823_si_cgu_inputs[] = { { "NONE", SI_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, { "NONE", SI_REF0N, DPLL_PIN_TYPE_UNSPEC, 0 }, - { "SYNCE0_DP", SI_REF1P, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "SYNCE0_DN", SI_REF1N, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + { "SYNCE0_DP", SI_REF1P, DPLL_PIN_TYPE_MUX, 0 }, + { "SYNCE0_DN", SI_REF1N, DPLL_PIN_TYPE_MUX, 0 }, { "EXT_CLK_SYNC", SI_REF2P, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "NONE", SI_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, { "EXT_PPS_OUT", SI_REF3, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "INT_PPS_OUT", SI_REF4, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, }; static const struct ice_cgu_pin_desc ice_e823_si_cgu_outputs[] = { { "1588-TIME_SYNC", SI_OUT0, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, - { "PHY-CLK", SI_OUT1, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, + { "PHY-CLK", SI_OUT1, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, { "10MHZ-SMA2", SI_OUT2, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz }, { "PPS-SMA1", SI_OUT3, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, }; static const struct ice_cgu_pin_desc ice_e823_zl_cgu_inputs[] = { { "NONE", ZL_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, { "INT_PPS_OUT", ZL_REF0N, DPLL_PIN_TYPE_EXT, - BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, - { "SYNCE0_DP", ZL_REF1P, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "SYNCE0_DN", ZL_REF1N, DPLL_PIN_TYPE_MUX, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, + { "SYNCE0_DP", ZL_REF1P, DPLL_PIN_TYPE_MUX, 0 }, + { "SYNCE0_DN", ZL_REF1N, DPLL_PIN_TYPE_MUX, 0 }, { "NONE", ZL_REF2P, DPLL_PIN_TYPE_UNSPEC, 0 }, { "NONE", ZL_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, { "EXT_CLK_SYNC", ZL_REF3P, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "NONE", ZL_REF3N, DPLL_PIN_TYPE_UNSPEC, 0 }, { "EXT_PPS_OUT", ZL_REF4P, DPLL_PIN_TYPE_EXT, - BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, - { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, + { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0 }, }; static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { { "PPS-SMA1", ZL_OUT0, DPLL_PIN_TYPE_EXT, - BIT(DPLL_PIN_FREQ_SUPP_1_HZ) }, + ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, { "10MHZ-SMA2", ZL_OUT1, DPLL_PIN_TYPE_EXT, - BIT(DPLL_PIN_FREQ_SUPP_10_MHZ) }, - { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, - { "1588-TIME_REF", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, - BIT(DPLL_PIN_FREQ_SUPP_UNSPEC) }, + ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz }, + { "PHY-CLK", ZL_OUT2, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, + { "1588-TIME_REF", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, { "CPK-TIME_SYNC", ZL_OUT4, DPLL_PIN_TYPE_EXT, - ICE_SIG_TYPE_MASK_1PPS_10MHZ }, + ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "NONE", ZL_OUT5, DPLL_PIN_TYPE_UNSPEC, 0 }, }; @@ -429,8 +419,8 @@ bool ice_is_clock_mux_present_e810t(struct ice_hw *hw); int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx); bool ice_is_cgu_present(struct ice_hw *hw); enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input); -unsigned long -ice_cgu_get_pin_freq_mask(struct ice_hw *hw, u8 pin, bool input); +struct dpll_pin_frequency * +ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num); const char *ice_cgu_get_pin_name(struct ice_hw *hw, u8 pin, bool input); int ice_get_cgu_state(struct ice_hw *hw, u8 dpll_idx, enum ice_cgu_state last_dpll_state, u8 *pin, From cc85fd1802d3e32579c8a65dc7997852d2dc0f64 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Sat, 11 Mar 2023 17:54:47 -0800 Subject: [PATCH 06/93] ptp_ocp: implement DPLL ops Implement basic DPLL operations in ptp_ocp driver as the simplest example of using new subsystem. Signed-off-by: Vadim Fedorenko --- drivers/ptp/Kconfig | 1 + drivers/ptp/ptp_ocp.c | 327 +++++++++++++++++++++++++++++++++++------- 2 files changed, 276 insertions(+), 52 deletions(-) diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index b00201d81313..e3575c2e34dc 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -177,6 +177,7 @@ config PTP_1588_CLOCK_OCP depends on COMMON_CLK select NET_DEVLINK select CRC16 + select DPLL help This driver adds support for an OpenCompute time card. diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index ab8cab4d1560..63d653329c9c 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -23,6 +23,7 @@ #include #include #include +#include #define PCI_VENDOR_ID_FACEBOOK 0x1d9b #define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 @@ -260,12 +261,21 @@ enum ptp_ocp_sma_mode { SMA_MODE_OUT, }; +static struct dpll_pin_frequency ptp_ocp_sma_freq[] = { + DPLL_PIN_FREQUENCY_1PPS, + DPLL_PIN_FREQUENCY_10MHZ, + DPLL_PIN_FREQUENCY_IRIG_B, + DPLL_PIN_FREQUENCY_DCF77, +}; + struct ptp_ocp_sma_connector { enum ptp_ocp_sma_mode mode; bool fixed_fcn; bool fixed_dir; bool disabled; u8 default_fcn; + struct dpll_pin *dpll_pin; + struct dpll_pin_properties dpll_prop; }; struct ocp_attr_group { @@ -294,6 +304,7 @@ struct ptp_ocp_serial_port { #define OCP_BOARD_ID_LEN 13 #define OCP_SERIAL_LEN 6 +#define OCP_SMA_NUM 4 struct ptp_ocp { struct pci_dev *pdev; @@ -350,8 +361,9 @@ struct ptp_ocp { u32 ts_window_adjust; u64 fw_cap; struct ptp_ocp_signal signal[4]; - struct ptp_ocp_sma_connector sma[4]; + struct ptp_ocp_sma_connector sma[OCP_SMA_NUM]; const struct ocp_sma_op *sma_op; + struct dpll_device *dpll; }; #define OCP_REQ_TIMESTAMP BIT(0) @@ -835,6 +847,7 @@ static DEFINE_IDR(ptp_ocp_idr); struct ocp_selector { const char *name; int value; + u64 frequency; }; static const struct ocp_selector ptp_ocp_clock[] = { @@ -855,31 +868,31 @@ static const struct ocp_selector ptp_ocp_clock[] = { #define SMA_SELECT_MASK GENMASK(14, 0) static const struct ocp_selector ptp_ocp_sma_in[] = { - { .name = "10Mhz", .value = 0x0000 }, - { .name = "PPS1", .value = 0x0001 }, - { .name = "PPS2", .value = 0x0002 }, - { .name = "TS1", .value = 0x0004 }, - { .name = "TS2", .value = 0x0008 }, - { .name = "IRIG", .value = 0x0010 }, - { .name = "DCF", .value = 0x0020 }, - { .name = "TS3", .value = 0x0040 }, - { .name = "TS4", .value = 0x0080 }, - { .name = "FREQ1", .value = 0x0100 }, - { .name = "FREQ2", .value = 0x0200 }, - { .name = "FREQ3", .value = 0x0400 }, - { .name = "FREQ4", .value = 0x0800 }, - { .name = "None", .value = SMA_DISABLE }, + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000 }, + { .name = "PPS1", .value = 0x0001, .frequency = 1 }, + { .name = "PPS2", .value = 0x0002, .frequency = 1 }, + { .name = "TS1", .value = 0x0004, .frequency = 0 }, + { .name = "TS2", .value = 0x0008, .frequency = 0 }, + { .name = "IRIG", .value = 0x0010, .frequency = 10000 }, + { .name = "DCF", .value = 0x0020, .frequency = 77500 }, + { .name = "TS3", .value = 0x0040, .frequency = 0 }, + { .name = "TS4", .value = 0x0080, .frequency = 0 }, + { .name = "FREQ1", .value = 0x0100, .frequency = 0 }, + { .name = "FREQ2", .value = 0x0200, .frequency = 0 }, + { .name = "FREQ3", .value = 0x0400, .frequency = 0 }, + { .name = "FREQ4", .value = 0x0800, .frequency = 0 }, + { .name = "None", .value = SMA_DISABLE, .frequency = 0 }, { } }; static const struct ocp_selector ptp_ocp_sma_out[] = { - { .name = "10Mhz", .value = 0x0000 }, - { .name = "PHC", .value = 0x0001 }, - { .name = "MAC", .value = 0x0002 }, - { .name = "GNSS1", .value = 0x0004 }, - { .name = "GNSS2", .value = 0x0008 }, - { .name = "IRIG", .value = 0x0010 }, - { .name = "DCF", .value = 0x0020 }, + { .name = "10Mhz", .value = 0x0000, .frequency = 10000000 }, + { .name = "PHC", .value = 0x0001, .frequency = 1 }, + { .name = "MAC", .value = 0x0002, .frequency = 1 }, + { .name = "GNSS1", .value = 0x0004, .frequency = 1 }, + { .name = "GNSS2", .value = 0x0008, .frequency = 1 }, + { .name = "IRIG", .value = 0x0010, .frequency = 10000 }, + { .name = "DCF", .value = 0x0020, .frequency = 77000 }, { .name = "GEN1", .value = 0x0040 }, { .name = "GEN2", .value = 0x0080 }, { .name = "GEN3", .value = 0x0100 }, @@ -890,15 +903,15 @@ static const struct ocp_selector ptp_ocp_sma_out[] = { }; static const struct ocp_selector ptp_ocp_art_sma_in[] = { - { .name = "PPS1", .value = 0x0001 }, - { .name = "10Mhz", .value = 0x0008 }, + { .name = "PPS1", .value = 0x0001, .frequency = 1 }, + { .name = "10Mhz", .value = 0x0008, .frequency = 1000000 }, { } }; static const struct ocp_selector ptp_ocp_art_sma_out[] = { - { .name = "PHC", .value = 0x0002 }, - { .name = "GNSS", .value = 0x0004 }, - { .name = "10Mhz", .value = 0x0010 }, + { .name = "PHC", .value = 0x0002, .frequency = 1 }, + { .name = "GNSS", .value = 0x0004, .frequency = 1 }, + { .name = "10Mhz", .value = 0x0010, .frequency = 10000000 }, { } }; @@ -2282,22 +2295,34 @@ ptp_ocp_sma_fb_set_inputs(struct ptp_ocp *bp, int sma_nr, u32 val) static void ptp_ocp_sma_fb_init(struct ptp_ocp *bp) { + struct dpll_pin_properties prop = { + .label = NULL, + .type = DPLL_PIN_TYPE_EXT, + .capabilities = DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE, + .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), + .freq_supported = ptp_ocp_sma_freq, + + }; u32 reg; int i; /* defaults */ + for (i = 0; i < OCP_SMA_NUM; i++) { + bp->sma[i].default_fcn = i & 1; + bp->sma[i].dpll_prop = prop; + bp->sma[i].dpll_prop.label = bp->ptp_info.pin_config[i].name; + } bp->sma[0].mode = SMA_MODE_IN; bp->sma[1].mode = SMA_MODE_IN; bp->sma[2].mode = SMA_MODE_OUT; bp->sma[3].mode = SMA_MODE_OUT; - for (i = 0; i < 4; i++) - bp->sma[i].default_fcn = i & 1; - /* If no SMA1 map, the pin functions and directions are fixed. */ if (!bp->sma_map1) { - for (i = 0; i < 4; i++) { + for (i = 0; i < OCP_SMA_NUM; i++) { bp->sma[i].fixed_fcn = true; bp->sma[i].fixed_dir = true; + bp->sma[1].dpll_prop.capabilities &= + ~DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; } return; } @@ -2307,7 +2332,7 @@ ptp_ocp_sma_fb_init(struct ptp_ocp *bp) */ reg = ioread32(&bp->sma_map2->gpio2); if (reg == 0xffffffff) { - for (i = 0; i < 4; i++) + for (i = 0; i < OCP_SMA_NUM; i++) bp->sma[i].fixed_dir = true; } else { reg = ioread32(&bp->sma_map1->gpio1); @@ -2329,7 +2354,7 @@ static const struct ocp_sma_op ocp_fb_sma_op = { }; static int -ptp_ocp_fb_set_pins(struct ptp_ocp *bp) +ptp_ocp_set_pins(struct ptp_ocp *bp) { struct ptp_pin_desc *config; int i; @@ -2396,16 +2421,16 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r) ptp_ocp_tod_init(bp); ptp_ocp_nmea_out_init(bp); - ptp_ocp_sma_init(bp); ptp_ocp_signal_init(bp); err = ptp_ocp_attr_group_add(bp, fb_timecard_groups); if (err) return err; - err = ptp_ocp_fb_set_pins(bp); + err = ptp_ocp_set_pins(bp); if (err) return err; + ptp_ocp_sma_init(bp); return ptp_ocp_init_clock(bp); } @@ -2445,6 +2470,14 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data) static void ptp_ocp_art_sma_init(struct ptp_ocp *bp) { + struct dpll_pin_properties prop = { + .label = NULL, + .type = DPLL_PIN_TYPE_EXT, + .capabilities = 0, + .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), + .freq_supported = ptp_ocp_sma_freq, + + }; u32 reg; int i; @@ -2459,16 +2492,16 @@ ptp_ocp_art_sma_init(struct ptp_ocp *bp) bp->sma[2].default_fcn = 0x10; /* OUT: 10Mhz */ bp->sma[3].default_fcn = 0x02; /* OUT: PHC */ - /* If no SMA map, the pin functions and directions are fixed. */ - if (!bp->art_sma) { - for (i = 0; i < 4; i++) { + + for (i = 0; i < OCP_SMA_NUM; i++) { + /* If no SMA map, the pin functions and directions are fixed. */ + bp->sma[i].dpll_prop = prop; + bp->sma[i].dpll_prop.label = bp->ptp_info.pin_config[i].name; + if (!bp->art_sma) { bp->sma[i].fixed_fcn = true; bp->sma[i].fixed_dir = true; + continue; } - return; - } - - for (i = 0; i < 4; i++) { reg = ioread32(&bp->art_sma->map[i].gpio); switch (reg & 0xff) { @@ -2479,9 +2512,13 @@ ptp_ocp_art_sma_init(struct ptp_ocp *bp) case 1: case 8: bp->sma[i].mode = SMA_MODE_IN; + bp->sma[i].dpll_prop.capabilities = + DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; break; default: bp->sma[i].mode = SMA_MODE_OUT; + bp->sma[i].dpll_prop.capabilities = + DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE; break; } } @@ -2548,6 +2585,9 @@ ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) /* Enable MAC serial port during initialisation */ iowrite32(1, &bp->board_config->mro50_serial_activate); + err = ptp_ocp_set_pins(bp); + if (err) + return err; ptp_ocp_sma_init(bp); err = ptp_ocp_attr_group_add(bp, art_timecard_groups); @@ -2689,16 +2729,9 @@ sma4_show(struct device *dev, struct device_attribute *attr, char *buf) } static int -ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) +ptp_ocp_sma_store_val(struct ptp_ocp *bp, int val, enum ptp_ocp_sma_mode mode, int sma_nr) { struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; - enum ptp_ocp_sma_mode mode; - int val; - - mode = sma->mode; - val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode); - if (val < 0) - return val; if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE)) return -EOPNOTSUPP; @@ -2733,6 +2766,20 @@ ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) return val; } +static int +ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) +{ + struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; + enum ptp_ocp_sma_mode mode; + int val; + + mode = sma->mode; + val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode); + if (val < 0) + return val; + return ptp_ocp_sma_store_val(bp, val, mode, sma_nr); +} + static ssize_t sma1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -4171,12 +4218,148 @@ ptp_ocp_detach(struct ptp_ocp *bp) device_unregister(&bp->dev); } +static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, + void *priv, + enum dpll_lock_status *status, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp *bp = priv; + int sync; + + sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; + *status = sync ? DPLL_LOCK_STATUS_LOCKED : DPLL_LOCK_STATUS_UNLOCKED; + + return 0; +} + +static int ptp_ocp_dpll_source_idx_get(const struct dpll_device *dpll, + void *priv, u32 *idx, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp *bp = priv; + + if (bp->pps_select) { + *idx = ioread32(&bp->pps_select->gpio1); + return 0; + } + return -EINVAL; +} + +static int ptp_ocp_dpll_mode_get(const struct dpll_device *dpll, void *priv, + u32 *mode, struct netlink_ext_ack *extack) +{ + *mode = DPLL_MODE_AUTOMATIC; + return 0; +} + +static bool ptp_ocp_dpll_mode_supported(const struct dpll_device *dpll, + void *priv, const enum dpll_mode mode, + struct netlink_ext_ack *extack) +{ + return mode == DPLL_MODE_AUTOMATIC; +} + +static int ptp_ocp_dpll_direction_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma = pin_priv; + + *direction = sma->mode == SMA_MODE_IN ? + DPLL_PIN_DIRECTION_SOURCE : + DPLL_PIN_DIRECTION_OUTPUT; + return 0; +} + +static int ptp_ocp_dpll_direction_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma = pin_priv; + struct ptp_ocp *bp = dpll_priv; + enum ptp_ocp_sma_mode mode; + int sma_nr = (sma - bp->sma); + + if (sma->fixed_dir) + return -EOPNOTSUPP; + mode = direction == DPLL_PIN_DIRECTION_SOURCE ? + SMA_MODE_IN : SMA_MODE_OUT; + return ptp_ocp_sma_store_val(bp, 0, mode, sma_nr); +} + +static int ptp_ocp_dpll_frequency_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 frequency, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma = pin_priv; + struct ptp_ocp *bp = dpll_priv; + const struct ocp_selector *tbl; + int sma_nr = (sma - bp->sma); + int val, i; + + if (sma->fixed_fcn) + return -EOPNOTSUPP; + + tbl = bp->sma_op->tbl[sma->mode]; + for (i = 0; tbl[i].name; i++) + if (tbl[i].frequency == frequency) + return ptp_ocp_sma_store_val(bp, val, sma->mode, sma_nr); + return -EINVAL; +} + +static int ptp_ocp_dpll_frequency_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, u64 *frequency, + struct netlink_ext_ack *extack) +{ + struct ptp_ocp_sma_connector *sma = pin_priv; + struct ptp_ocp *bp = dpll_priv; + const struct ocp_selector *tbl; + int sma_nr = (sma - bp->sma); + u32 val; + int i; + + val = bp->sma_op->get(bp, sma_nr); + tbl = bp->sma_op->tbl[sma->mode]; + for (i = 0; tbl[i].name; i++) + if (val == tbl[i].value) { + *frequency = tbl[i].frequency; + return 0; + } + + return -EINVAL; +} + +static const struct dpll_device_ops dpll_ops = { + .lock_status_get = ptp_ocp_dpll_lock_status_get, + .source_pin_idx_get = ptp_ocp_dpll_source_idx_get, + .mode_get = ptp_ocp_dpll_mode_get, + .mode_supported = ptp_ocp_dpll_mode_supported, +}; + +static const struct dpll_pin_ops dpll_pins_ops = { + .frequency_get = ptp_ocp_dpll_frequency_get, + .frequency_set = ptp_ocp_dpll_frequency_set, + .direction_get = ptp_ocp_dpll_direction_get, + .direction_set = ptp_ocp_dpll_direction_set, +}; + static int ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct devlink *devlink; struct ptp_ocp *bp; - int err; + int err, i; + u64 clkid; devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev); if (!devlink) { @@ -4226,8 +4409,39 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) ptp_ocp_info(bp); devlink_register(devlink); - return 0; + clkid = pci_get_dsn(pdev); + bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); + if (IS_ERR(bp->dpll)) { + dev_err(&pdev->dev, "dpll_device_alloc failed\n"); + goto out; + } + + err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp, &pdev->dev); + if (err) + goto out; + + for (i = 0; i < OCP_SMA_NUM; i++) { + bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop); + if (IS_ERR(bp->sma[i].dpll_pin)) + goto out_dpll; + + err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, + &bp->sma[i], NULL); + if (err) { + dpll_pin_put(bp->sma[i].dpll_pin); + goto out_dpll; + } + } + + return 0; +out_dpll: + while (i) { + --i; + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); + dpll_pin_put(bp->sma[i].dpll_pin); + } + dpll_device_put(bp->dpll); out: ptp_ocp_detach(bp); out_disable: @@ -4242,7 +4456,16 @@ ptp_ocp_remove(struct pci_dev *pdev) { struct ptp_ocp *bp = pci_get_drvdata(pdev); struct devlink *devlink = priv_to_devlink(bp); + int i; + for (i = 0; i < OCP_SMA_NUM; i++) { + if (bp->sma[i].dpll_pin) { + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, bp); + dpll_pin_put(bp->sma[i].dpll_pin); + } + } + dpll_device_unregister(bp->dpll, &dpll_ops, bp); + dpll_device_put(bp->dpll); devlink_unregister(devlink); ptp_ocp_detach(bp); pci_disable_device(pdev); From 864502d5dd91dc7620661937d024307af4f6c1ef Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Wed, 29 Mar 2023 02:29:44 +0300 Subject: [PATCH 07/93] netdev: expose DPLL pin handle for netdevice In case netdevice represents a SyncE port, the user needs to understand the connection between netdevice and associated DPLL pin. There might me multiple netdevices pointing to the same pin, in case of VF/SF implementation. Add a IFLA Netlink attribute to nest the DPLL pin handle, similar to how is is implemented for devlink port. Add a struct dpll_pin pointer to netdev and protect access to it by RTNL. Expose netdev_dpll_pin_set() and netdev_dpll_pin_clear() helpers to the drivers so they can set/clear the DPLL pin relationship to netdev. Note that during the lifetime of struct dpll_pin the handle fields do not change. Therefore it is save to access them lockless. It is drivers responsibility to call netdev_dpll_pin_clear() before dpll_pin_put(). Signed-off-by: Jiri Pirko --- drivers/dpll/dpll_netlink.c | 23 ++++++++++++++++++++-- include/linux/dpll.h | 20 +++++++++++++++++++ include/linux/netdevice.h | 7 +++++++ include/uapi/linux/if_link.h | 2 ++ net/core/dev.c | 20 +++++++++++++++++++ net/core/rtnetlink.c | 38 ++++++++++++++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 2 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 1eb0b4a2fce4..734b6776b07c 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -269,8 +269,9 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, { int ret; - if (nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) - return -EMSGSIZE; + ret = dpll_msg_add_pin_handle(msg, pin); + if (ret) + return ret; if (nla_put_string(msg, DPLL_A_PIN_LABEL, pin->prop.label)) return -EMSGSIZE; if (nla_put_u8(msg, DPLL_A_PIN_TYPE, pin->prop.type)) @@ -290,6 +291,24 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, return 0; } +size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) +{ + // TMP- THE HANDLE IS GOING TO CHANGE TO DRIVERNAME/CLOCKID/PIN_INDEX + // LEAVING ORIG HANDLE NOW AS PUT IN THE LAST RFC VERSION + return nla_total_size(4); /* DPLL_A_PIN_IDX */ +} +EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size); + +int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) +{ + // TMP- THE HANDLE IS GOING TO CHANGE TO DRIVERNAME/CLOCKID/PIN_INDEX + // LEAVING ORIG HANDLE NOW AS PUT IN THE LAST RFC VERSION + if (nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) + return -EMSGSIZE; + return 0; +} +EXPORT_SYMBOL_GPL(dpll_msg_add_pin_handle); + static int __dpll_cmd_pin_dump_one(struct sk_buff *msg, struct dpll_pin *pin, struct netlink_ext_ack *extack) diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 5194efaf55a8..5945bb456794 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -104,6 +104,26 @@ struct dpll_pin_properties { struct dpll_pin_frequency *freq_supported; }; +#if IS_ENABLED(CONFIG_DPLL) + +size_t dpll_msg_pin_handle_size(struct dpll_pin *pin); + +int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin); + +#else + +static inline size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) +{ + return 0; +} + +static inline int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) +{ + return 0; +} + +#endif + /** * dpll_device_get - find or create dpll_device object * @clock_id: a system unique number for a device diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 08fbd4622ccf..be162d8db611 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef CONFIG_DCB @@ -2411,6 +2412,10 @@ struct net_device { struct rtnl_hw_stats64 *offload_xstats_l3; struct devlink_port *devlink_port; + +#if IS_ENABLED(CONFIG_DPLL) + struct dpll_pin *dpll_pin; +#endif }; #define to_net_dev(d) container_of(d, struct net_device, dev) @@ -3954,6 +3959,8 @@ int dev_get_mac_address(struct sockaddr *sa, struct net *net, char *dev_name); int dev_get_port_parent_id(struct net_device *dev, struct netdev_phys_item_id *ppid, bool recurse); bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b); +void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin); +void netdev_dpll_pin_clear(struct net_device *dev); struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again); struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 0f6a0fe09bdb..be03c8292cd7 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -377,6 +377,8 @@ enum { IFLA_GSO_IPV4_MAX_SIZE, IFLA_GRO_IPV4_MAX_SIZE, + IFLA_DPLL_PIN, + __IFLA_MAX }; diff --git a/net/core/dev.c b/net/core/dev.c index 99d99b247bc9..ef4a827a519e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8993,6 +8993,26 @@ bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b) } EXPORT_SYMBOL(netdev_port_same_parent_id); +static void netdev_dpll_pin_assign(struct net_device *dev, struct dpll_pin *dpll_pin) +{ + rtnl_lock(); + dev->dpll_pin = dpll_pin; + rtnl_unlock(); +} + +void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) +{ + WARN_ON(!dpll_pin); + netdev_dpll_pin_assign(dev, dpll_pin); +} +EXPORT_SYMBOL(netdev_dpll_pin_set); + +void netdev_dpll_pin_clear(struct net_device *dev) +{ + netdev_dpll_pin_assign(dev, NULL); +} +EXPORT_SYMBOL(netdev_dpll_pin_clear); + /** * dev_change_proto_down - set carrier according to proto_down. * diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 41de3a2f29e1..ebe9ae8608fc 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1052,6 +1052,16 @@ static size_t rtnl_devlink_port_size(const struct net_device *dev) return size; } +static size_t rtnl_dpll_pin_size(const struct net_device *dev) +{ + size_t size = nla_total_size(0); /* nest IFLA_DPLL_PIN */ + + if (dev->dpll_pin) + size += dpll_msg_pin_handle_size(dev->dpll_pin); + + return size; +} + static noinline size_t if_nlmsg_size(const struct net_device *dev, u32 ext_filter_mask) { @@ -1108,6 +1118,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + rtnl_prop_list_size(dev) + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */ + rtnl_devlink_port_size(dev) + + rtnl_dpll_pin_size(dev) + 0; } @@ -1769,6 +1780,30 @@ static int rtnl_fill_devlink_port(struct sk_buff *skb, return ret; } +static int rtnl_fill_dpll_pin(struct sk_buff *skb, + const struct net_device *dev) +{ + struct nlattr *dpll_pin_nest; + int ret; + + dpll_pin_nest = nla_nest_start(skb, IFLA_DPLL_PIN); + if (!dpll_pin_nest) + return -EMSGSIZE; + + if (dev->dpll_pin) { + ret = dpll_msg_add_pin_handle(skb, dev->dpll_pin); + if (ret < 0) + goto nest_cancel; + } + + nla_nest_end(skb, dpll_pin_nest); + return 0; + +nest_cancel: + nla_nest_cancel(skb, dpll_pin_nest); + return ret; +} + static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, struct net *src_net, int type, u32 pid, u32 seq, u32 change, @@ -1911,6 +1946,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, if (rtnl_fill_devlink_port(skb, dev)) goto nla_put_failure; + if (rtnl_fill_dpll_pin(skb, dev)) + goto nla_put_failure; + nlmsg_end(skb, nlh); return 0; From 5ba1b50d00ff84d18932a198d9dff5b2e75ade98 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 29 Mar 2023 02:31:15 +0300 Subject: [PATCH 08/93] mlx5: Implement SyncE support using DPLL infrastructure Implement SyncE support using newly introduced DPLL support. Make sure that each PFs/VFs/SFs probed with appropriate capability will spawn a dpll auxiliary device and register appropriate dpll device and pin instances. Signed-off-by: Jiri Pirko --- .../net/ethernet/mellanox/mlx5/core/Kconfig | 8 + .../net/ethernet/mellanox/mlx5/core/Makefile | 3 + drivers/net/ethernet/mellanox/mlx5/core/dev.c | 17 + .../net/ethernet/mellanox/mlx5/core/dpll.c | 438 ++++++++++++++++++ include/linux/mlx5/driver.h | 2 + include/linux/mlx5/mlx5_ifc.h | 59 ++- 6 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/dpll.c diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index bb1d7b039a7e..15a48d376eb3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -188,3 +188,11 @@ config MLX5_SF_MANAGER port is managed through devlink. A subfunction supports RDMA, netdevice and vdpa device. It is similar to a SRIOV VF but it doesn't require SRIOV support. + +config MLX5_DPLL + tristate "Mellanox 5th generation network adapters (ConnectX series) DPLL support" + depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE + select DPLL + help + DPLL support in Mellanox Technologies ConnectX NICs. + diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index ddf1e352f51d..69434e8c2fb1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -123,3 +123,6 @@ mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o irq_ # SF manager # mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o + +obj-$(CONFIG_MLX5_DPLL) += mlx5_dpll.o +mlx5_dpll-y := dpll.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 1b33533b15de..7d677332a18b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -211,6 +211,19 @@ static bool is_ib_enabled(struct mlx5_core_dev *dev) return err ? false : val.vbool; } +static bool is_dpll_supported(struct mlx5_core_dev *dev) +{ + if (!IS_ENABLED(CONFIG_MLX5_DPLL)) + return false; + + if (!MLX5_CAP_MCAM_REG2(dev, synce_registers)) { + mlx5_core_warn(dev, "Missing SyncE capability\n"); + return false; + } + + return true; +} + enum { MLX5_INTERFACE_PROTOCOL_ETH, MLX5_INTERFACE_PROTOCOL_ETH_REP, @@ -220,6 +233,8 @@ enum { MLX5_INTERFACE_PROTOCOL_MPIB, MLX5_INTERFACE_PROTOCOL_VNET, + + MLX5_INTERFACE_PROTOCOL_DPLL, }; static const struct mlx5_adev_device { @@ -242,6 +257,8 @@ static const struct mlx5_adev_device { .is_supported = &is_ib_rep_supported }, [MLX5_INTERFACE_PROTOCOL_MPIB] = { .suffix = "multiport", .is_supported = &is_mp_supported }, + [MLX5_INTERFACE_PROTOCOL_DPLL] = { .suffix = "dpll", + .is_supported = &is_dpll_supported }, }; int mlx5_adev_idx_alloc(void) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c new file mode 100644 index 000000000000..1469ddbafec7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include +#include + +// POSSIBLE DPLL API EXTENSIONS: +// 1) Expose clock quality: MSECQ->local_ssm_code, MSECQ->local_enhanced_ssm_code +// Proposed enum: +// QL_DNU, +// QL_EEC1, +// QL_eEEC, +// QL_SSU_B, +// QL_SSU_A, +// QL_PRC, +// QL_ePRC, +// QL_PRTC, +// QL_ePRTC, +// 2) Expose possibility to do holdover: MSEES->ho_acq +// 3) DPLL Implementation hw-speficic values (debug?): MSEES->oper_freq_measure + +/* This structure represents a reference to DPLL, one is created + * per mdev instance. + */ +struct mlx5_dpll { + struct dpll_device *dpll; + struct dpll_pin *dpll_pin; + struct mlx5_core_dev *mdev; + struct workqueue_struct *wq; + struct delayed_work work; + struct { + bool valid; + enum dpll_lock_status lock_status; + enum dpll_pin_state pin_state; + } last; + struct notifier_block mdev_nb; + struct net_device *tracking_netdev; +}; + +static int mlx5_dpll_clock_id_get(struct mlx5_core_dev *mdev, u64 *clock_id) +{ + u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {}; + int err; + + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), + MLX5_REG_MSECQ, 0, 0); + if (err) + return err; + *clock_id = MLX5_GET64(msecq_reg, out, local_clock_identity); + return 0; +} + +static int +mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, + enum mlx5_msees_admin_status *admin_status, + enum mlx5_msees_oper_status *oper_status) +{ + u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; + int err; + + MLX5_SET(msees_reg, in, local_port, 1); + err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), + MLX5_REG_MSEES, 0, 0); + if (err) + return err; + if (admin_status) + *admin_status = MLX5_GET(msees_reg, out, admin_status); + if (oper_status) + *oper_status = MLX5_GET(msees_reg, out, oper_status); + return 0; +} + +static int +mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev, + enum mlx5_msees_admin_status admin_status) +{ + u32 out[MLX5_ST_SZ_DW(msees_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(msees_reg)] = {}; + + MLX5_SET(msees_reg, in, local_port, 1); + MLX5_SET(msees_reg, in, field_select, + MLX5_MSEES_FIELD_SELECT_ENABLE | + MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS); + MLX5_SET(msees_reg, in, admin_status, admin_status); + MLX5_SET(msees_reg, in, admin_freq_measure, + admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK); + return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), + MLX5_REG_MSEES, 0, 0); +} + +static enum dpll_lock_status +mlx5_dpll_lock_status_from_oper_status(enum mlx5_msees_oper_status oper_status) +{ + switch (oper_status) { + case MLX5_MSEES_OPER_STATUS_SELF_TRACK: + fallthrough; + case MLX5_MSEES_OPER_STATUS_OTHER_TRACK: + return DPLL_LOCK_STATUS_LOCKED; + case MLX5_MSEES_OPER_STATUS_HOLDOVER: + return DPLL_LOCK_STATUS_HOLDOVER; + default: + return DPLL_LOCK_STATUS_UNLOCKED; + } +} + +static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, + void *priv, + enum dpll_lock_status *status, + struct netlink_ext_ack *extack) +{ + enum mlx5_msees_oper_status oper_status; + struct mlx5_dpll *mdpll = priv; + int err; + + err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL, &oper_status); + if (err) + return err; + + *status = mlx5_dpll_lock_status_from_oper_status(oper_status); + return 0; +} + +static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll, + void *priv, + u32 *mode, struct netlink_ext_ack *extack) +{ + *mode = DPLL_MODE_MANUAL; + return 0; +} + +static bool mlx5_dpll_device_mode_supported(const struct dpll_device *dpll, + void *priv, + enum dpll_mode mode, + struct netlink_ext_ack *extack) +{ + return mode == DPLL_MODE_MANUAL; +} + +static const struct dpll_device_ops mlx5_dpll_device_ops = { + .lock_status_get = mlx5_dpll_device_lock_status_get, + .mode_get = mlx5_dpll_device_mode_get, + .mode_supported = mlx5_dpll_device_mode_supported, +}; + +static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) +{ + *direction = DPLL_PIN_DIRECTION_SOURCE; + return 0; +} + +static enum dpll_pin_state +mlx5_dpll_pin_state_from_admin_status(enum mlx5_msees_admin_status admin_status) +{ + return admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK ? + DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED; +} + +static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) +{ + enum mlx5_msees_admin_status admin_status; + struct mlx5_dpll *mdpll = pin_priv; + int err; + + err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, NULL); + if (err) + return err; + *state = mlx5_dpll_pin_state_from_admin_status(admin_status); + return 0; +} + +static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin, + void *pin_priv, + const struct dpll_device *dpll, + void *dpll_priv, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) +{ + struct mlx5_dpll *mdpll = pin_priv; + + return mlx5_dpll_synce_status_set(mdpll->mdev, + state == DPLL_PIN_STATE_CONNECTED ? + MLX5_MSEES_ADMIN_STATUS_TRACK : + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); +} + +static const struct dpll_pin_ops mlx5_dpll_pins_ops = { + .direction_get = mlx5_dpll_pin_direction_get, + .state_on_dpll_get = mlx5_dpll_state_on_dpll_get, + .state_on_dpll_set = mlx5_dpll_state_on_dpll_set, +}; + +static const struct dpll_pin_properties mlx5_dpll_pin_properties = { + .label = "n/a", + .type = DPLL_PIN_TYPE_SYNCE_ETH_PORT, + .capabilities = DPLL_PIN_CAPS_STATE_CAN_CHANGE, +}; + +#define MLX5_DPLL_PERIODIC_WORK_INTERVAL 500 /* ms */ + +static void mlx5_dpll_periodic_work_queue(struct mlx5_dpll *mdpll) +{ + queue_delayed_work(mdpll->wq, &mdpll->work, + msecs_to_jiffies(MLX5_DPLL_PERIODIC_WORK_INTERVAL)); +} + +static void mlx5_dpll_periodic_work(struct work_struct *work) +{ + struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll, + work.work); + enum mlx5_msees_admin_status admin_status; + enum mlx5_msees_oper_status oper_status; + enum dpll_lock_status lock_status; + enum dpll_pin_state pin_state, + + err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status, + &oper_status); + if (err) + goto err_out; + lock_status = mlx5_dpll_lock_status_from_oper_status(oper_status); + pin_state = mlx5_dpll_pin_state_from_admin_status(admin_status); + + if (!mdpll->last.valid) + goto invalid_out; + + if (mdpll->last.lock_status != lock_status) + dpll_device_notify(mdpll->dpll, DPLL_A_LOCK_STATUS); + if (mdpll->last.pin_state != pin_state) + dpll_pin_notify(mdpll->dpll, mdpll->dpll_pin, DPLL_A_PIN_STATE); + +invalid_out: + mdpll->last.lock_status = lock_status; + mdpll->last.pin_state = pin_state; + mdpll->last.valid = true; +err_out: + mlx5_dpll_periodic_work_queue(mdpll); +} + +static void mlx5_dpll_netdev_dpll_pin_set(struct mlx5_dpll *mdpll, + struct net_device *netdev) +{ + if (mdpll->tracking_netdev) + return; + netdev_dpll_pin_set(netdev, mdpll->dpll_pin); + mdpll->tracking_netdev = netdev; +} + +static void mlx5_dpll_netdev_dpll_pin_clear(struct mlx5_dpll *mdpll) +{ + if (!mdpll->tracking_netdev) + return; + netdev_dpll_pin_clear(mdpll->tracking_netdev); + mdpll->tracking_netdev = NULL; +} + +static int mlx5_dpll_mdev_notifier_event(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct mlx5_dpll *mdpll = container_of(nb, struct mlx5_dpll, mdev_nb); + struct net_device *netdev = data; + + switch (event) { + case MLX5_DRIVER_EVENT_UPLINK_NETDEV: + if (netdev) + mlx5_dpll_netdev_dpll_pin_set(mdpll, netdev); + else + mlx5_dpll_netdev_dpll_pin_clear(mdpll); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static void mlx5_dpll_mdev_netdev_track(struct mlx5_dpll *mdpll, + struct mlx5_core_dev *mdev) +{ + mdpll->mdev_nb.notifier_call = mlx5_dpll_mdev_notifier_event; + mlx5_blocking_notifier_register(mdev, &mdpll->mdev_nb); + mlx5_core_uplink_netdev_event_replay(mdev); +} + +static void mlx5_dpll_mdev_netdev_untrack(struct mlx5_dpll *mdpll, + struct mlx5_core_dev *mdev) +{ + mlx5_blocking_notifier_unregister(mdev, &mdpll->mdev_nb); + mlx5_dpll_netdev_dpll_pin_clear(mdpll); +} + +static int mlx5_dpll_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev); + struct mlx5_core_dev *mdev = edev->mdev; + struct mlx5_dpll *mdpll; + u64 clock_id; + int err; + + err = mlx5_dpll_synce_status_set(mdev, + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); + if (err) + return err; + + err = mlx5_dpll_clock_id_get(mdev, &clock_id); + if (err) + return err; + + mdpll = kzalloc(sizeof(*mdpll), GFP_KERNEL); + if (!mdpll) + return -ENOMEM; + mdpll->mdev = mdev; + auxiliary_set_drvdata(adev, mdpll); + + /* Multiple mdev instances might share one DPLL device. */ + mdpll->dpll = dpll_device_get(clock_id, 0, THIS_MODULE); + if (IS_ERR(mdpll->dpll)) { + err = PTR_ERR(mdpll->dpll); + goto err_free_mdpll; + } + + err = dpll_device_register(mdpll->dpll, DPLL_TYPE_EEC, + &mlx5_dpll_device_ops, mdpll, &adev->dev); + if (err) + goto err_put_dpll_device; + + /* Multiple mdev instances might share one DPLL pin. */ + mdpll->dpll_pin = dpll_pin_get(clock_id, mlx5_get_dev_index(mdev), + THIS_MODULE, &mlx5_dpll_pin_properties); + if (IS_ERR(mdpll->dpll_pin)) { + err = PTR_ERR(mdpll->dpll_pin); + goto err_unregister_dpll_device; + } + + err = dpll_pin_register(mdpll->dpll, mdpll->dpll_pin, + &mlx5_dpll_pins_ops, mdpll, NULL); + if (err) + goto err_put_dpll_pin; + + mdpll->wq = create_singlethread_workqueue("mlx5_dpll"); + if (!mdpll->wq) { + err = -ENOMEM; + goto err_unregister_dpll_pin; + } + + mlx5_dpll_mdev_netdev_track(mdpll, mdev); + + INIT_DELAYED_WORK(&mdpll->work, &mlx5_dpll_periodic_work); + mlx5_dpll_periodic_work_queue(mdpll); + + return 0; + +err_unregister_dpll_pin: + dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, + &mlx5_dpll_pins_ops, mdpll); +err_put_dpll_pin: + dpll_pin_put(mdpll->dpll_pin); +err_unregister_dpll_device: + dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); +err_put_dpll_device: + dpll_device_put(mdpll->dpll); +err_free_mdpll: + kfree(mdpll); + return err; +} + +static void mlx5_dpll_remove(struct auxiliary_device *adev) +{ + struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev); + struct mlx5_core_dev *mdev = mdpll->mdev; + + cancel_delayed_work(&mdpll->work); + mlx5_dpll_mdev_netdev_untrack(mdpll, mdev); + destroy_workqueue(mdpll->wq); + dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin, + &mlx5_dpll_pins_ops, mdpll); + dpll_pin_put(mdpll->dpll_pin); + dpll_device_unregister(mdpll->dpll, &mlx5_dpll_device_ops, mdpll); + dpll_device_put(mdpll->dpll); + kfree(mdpll); + + mlx5_dpll_synce_status_set(mdev, + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING); +} + +static int mlx5_dpll_suspend(struct auxiliary_device *adev, pm_message_t state) +{ + return 0; +} + +static int mlx5_dpll_resume(struct auxiliary_device *adev) +{ + return 0; +} + +static const struct auxiliary_device_id mlx5_dpll_id_table[] = { + { .name = MLX5_ADEV_NAME ".dpll", }, + {}, +}; + +MODULE_DEVICE_TABLE(auxiliary, mlx5_dpll_id_table); + +static struct auxiliary_driver mlx5_dpll_driver = { + .name = "dpll", + .probe = mlx5_dpll_probe, + .remove = mlx5_dpll_remove, + .suspend = mlx5_dpll_suspend, + .resume = mlx5_dpll_resume, + .id_table = mlx5_dpll_id_table, +}; + +static int __init mlx5_dpll_init(void) +{ + return auxiliary_driver_register(&mlx5_dpll_driver); +} + +static void __exit mlx5_dpll_exit(void) +{ + auxiliary_driver_unregister(&mlx5_dpll_driver); +} + +module_init(mlx5_dpll_init); +module_exit(mlx5_dpll_exit); + +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) DPLL driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 94d2be5848ae..e063af87b552 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -154,6 +154,8 @@ enum { MLX5_REG_MCC = 0x9062, MLX5_REG_MCDA = 0x9063, MLX5_REG_MCAM = 0x907f, + MLX5_REG_MSECQ = 0x9155, + MLX5_REG_MSEES = 0x9156, MLX5_REG_MIRC = 0x9162, MLX5_REG_SBCAM = 0xB01F, MLX5_REG_RESOURCE_DUMP = 0xC000, diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index b89778d0d326..1381c668684f 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -10193,7 +10193,9 @@ struct mlx5_ifc_mcam_access_reg_bits2 { u8 mirc[0x1]; u8 regs_97_to_96[0x2]; - u8 regs_95_to_64[0x20]; + u8 regs_95_to_87[0x09]; + u8 synce_registers[0x2]; + u8 regs_84_to_64[0x15]; u8 regs_63_to_32[0x20]; @@ -12555,4 +12557,59 @@ struct mlx5_ifc_modify_page_track_obj_in_bits { struct mlx5_ifc_page_track_bits obj_context; }; +struct mlx5_ifc_msecq_reg_bits { + u8 reserved_at_0[0x20]; + + u8 reserved_at_20[0x12]; + u8 network_option[0x2]; + u8 local_ssm_code[0x4]; + u8 local_enhanced_ssm_code[0x8]; + + u8 local_clock_identity[0x40]; + + u8 reserved_at_80[0x180]; +}; + +enum { + MLX5_MSEES_FIELD_SELECT_ENABLE = BIT(0), + MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS = BIT(1), + MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE = BIT(2), +}; + +enum mlx5_msees_admin_status { + MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING = 0x0, + MLX5_MSEES_ADMIN_STATUS_TRACK = 0x1, +}; + +enum mlx5_msees_oper_status { + MLX5_MSEES_OPER_STATUS_FREE_RUNNING = 0x0, + MLX5_MSEES_OPER_STATUS_SELF_TRACK = 0x1, + MLX5_MSEES_OPER_STATUS_OTHER_TRACK = 0x2, + MLX5_MSEES_OPER_STATUS_HOLDOVER = 0x3, + MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER = 0x4, + MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING = 0x5, +}; + +struct mlx5_ifc_msees_reg_bits { + u8 reserved_at_0[0x8]; + u8 local_port[0x8]; + u8 pnat[0x2]; + u8 lp_msb[0x2]; + u8 reserved_at_14[0xc]; + + u8 field_select[0x20]; + + u8 admin_status[0x4]; + u8 oper_status[0x4]; + u8 ho_acq[0x1]; + u8 reserved_at_49[0xc]; + u8 admin_freq_measure[0x1]; + u8 oper_freq_measure[0x1]; + u8 failure_reason[0x9]; + + u8 frequency_diff[0x20]; + + u8 reserved_at_80[0x180]; +}; + #endif /* MLX5_IFC_H */ From ebd79649cd82c98aafbc1d910b69fb69eef9ce1b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 11:49:58 +0200 Subject: [PATCH 09/93] dpll: spec: remove unspec attributes Attributes are not used, remove them and start with a value given. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 33 +++++++-------------------- include/uapi/linux/dpll.h | 33 +++++++-------------------- 2 files changed, 16 insertions(+), 50 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 67ca0f6cf2d5..7b847038a511 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -13,12 +13,10 @@ definitions: one of its sources to syntonize with it, valid values for DPLL_A_MODE attribute entries: - - - name: unspec - doc: unspecified value - name: manual doc: source can be only selected by sending a request to dpll + value: 1 - name: automatic doc: highest prio, valid source, auto selected by dpll @@ -39,14 +37,12 @@ definitions: provides information of dpll device lock status, valid values for DPLL_A_LOCK_STATUS attribute entries: - - - name: unspec - doc: unspecified value - name: unlocked doc: | dpll was not yet locked to any valid source (or is in one of modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) + value: 1 - name: calibrating doc: dpll is trying to lock to a valid signal @@ -75,12 +71,10 @@ definitions: name: type doc: type of dpll, valid values for DPLL_A_TYPE attribute entries: - - - name: unspec - doc: unspecified value - name: pps doc: dpll produces Pulse-Per-Second signal + value: 1 - name: eec doc: dpll drives the Ethernet Equipment Clock @@ -92,12 +86,10 @@ definitions: defines possible types of a pin, valid values for DPLL_A_PIN_TYPE attribute entries: - - - name: unspec - doc: unspecified value - name: mux doc: aggregates another layer of selectable pins + value: 1 - name: ext doc: external source @@ -118,12 +110,10 @@ definitions: defines possible direction of a pin, valid values for DPLL_A_PIN_DIRECTION attribute entries: - - - name: unspec - doc: unspecified value - name: source doc: pin used as a source of a signal + value: 1 - name: output doc: pin used to output the signal @@ -143,12 +133,10 @@ definitions: defines possible states of a pin, valid values for DPLL_A_PIN_STATE attribute entries: - - - name: unspec - doc: unspecified value - name: connected doc: pin connected, active source of phase locked loop + value: 1 - name: disconnected doc: pin disconnected, not considered as a valid source @@ -174,12 +162,10 @@ definitions: name: event doc: events of dpll generic netlink family entries: - - - name: unspec - doc: invalid event type - name: device-create doc: dpll device created + value: 1 - name: device-delete doc: dpll device deleted @@ -357,14 +343,11 @@ attribute-sets: operations: list: - - - name: unspec - doc: unused - - name: device-get doc: | Get list of DPLL devices (dump) or attributes of a single dpll device + value: 1 attribute-set: dpll flags: [ admin-perm ] diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 75eeaa4396eb..b8a427cb4712 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -13,7 +13,6 @@ * enum dpll_mode - working-modes a dpll can support, differentiate if and how * dpll selects one of its sources to syntonize with it, valid values for * DPLL_A_MODE attribute - * @DPLL_MODE_UNSPEC: unspecified value * @DPLL_MODE_MANUAL: source can be only selected by sending a request to dpll * @DPLL_MODE_AUTOMATIC: highest prio, valid source, auto selected by dpll * @DPLL_MODE_HOLDOVER: dpll forced into holdover mode @@ -21,8 +20,7 @@ * @DPLL_MODE_NCO: dpll driven by Numerically Controlled Oscillator */ enum dpll_mode { - DPLL_MODE_UNSPEC, - DPLL_MODE_MANUAL, + DPLL_MODE_MANUAL = 1, DPLL_MODE_AUTOMATIC, DPLL_MODE_HOLDOVER, DPLL_MODE_FREERUN, @@ -35,7 +33,6 @@ enum dpll_mode { /** * enum dpll_lock_status - provides information of dpll device lock status, * valid values for DPLL_A_LOCK_STATUS attribute - * @DPLL_LOCK_STATUS_UNSPEC: unspecified value * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid source (or * is in one of modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) * @DPLL_LOCK_STATUS_CALIBRATING: dpll is trying to lock to a valid signal @@ -44,8 +41,7 @@ enum dpll_mode { * was forced by selecting DPLL_MODE_HOLDOVER mode */ enum dpll_lock_status { - DPLL_LOCK_STATUS_UNSPEC, - DPLL_LOCK_STATUS_UNLOCKED, + DPLL_LOCK_STATUS_UNLOCKED = 1, DPLL_LOCK_STATUS_CALIBRATING, DPLL_LOCK_STATUS_LOCKED, DPLL_LOCK_STATUS_HOLDOVER, @@ -58,13 +54,11 @@ enum dpll_lock_status { /** * enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute - * @DPLL_TYPE_UNSPEC: unspecified value * @DPLL_TYPE_PPS: dpll produces Pulse-Per-Second signal * @DPLL_TYPE_EEC: dpll drives the Ethernet Equipment Clock */ enum dpll_type { - DPLL_TYPE_UNSPEC, - DPLL_TYPE_PPS, + DPLL_TYPE_PPS = 1, DPLL_TYPE_EEC, __DPLL_TYPE_MAX, @@ -74,7 +68,6 @@ enum dpll_type { /** * enum dpll_pin_type - defines possible types of a pin, valid values for * DPLL_A_PIN_TYPE attribute - * @DPLL_PIN_TYPE_UNSPEC: unspecified value * @DPLL_PIN_TYPE_MUX: aggregates another layer of selectable pins * @DPLL_PIN_TYPE_EXT: external source * @DPLL_PIN_TYPE_SYNCE_ETH_PORT: ethernet port PHY's recovered clock @@ -82,8 +75,7 @@ enum dpll_type { * @DPLL_PIN_TYPE_GNSS: GNSS recovered clock */ enum dpll_pin_type { - DPLL_PIN_TYPE_UNSPEC, - DPLL_PIN_TYPE_MUX, + DPLL_PIN_TYPE_MUX = 1, DPLL_PIN_TYPE_EXT, DPLL_PIN_TYPE_SYNCE_ETH_PORT, DPLL_PIN_TYPE_INT_OSCILLATOR, @@ -96,13 +88,11 @@ enum dpll_pin_type { /** * enum dpll_pin_direction - defines possible direction of a pin, valid values * for DPLL_A_PIN_DIRECTION attribute - * @DPLL_PIN_DIRECTION_UNSPEC: unspecified value * @DPLL_PIN_DIRECTION_SOURCE: pin used as a source of a signal * @DPLL_PIN_DIRECTION_OUTPUT: pin used to output the signal */ enum dpll_pin_direction { - DPLL_PIN_DIRECTION_UNSPEC, - DPLL_PIN_DIRECTION_SOURCE, + DPLL_PIN_DIRECTION_SOURCE = 1, DPLL_PIN_DIRECTION_OUTPUT, __DPLL_PIN_DIRECTION_MAX, @@ -111,21 +101,17 @@ enum dpll_pin_direction { #define DPLL_PIN_FREQUENCY_1_HZ 1 #define DPLL_PIN_FREQUENCY_10_MHZ 10000000 -#define DPLL_PIN_FREQUENCY_10_KHZ 10000 -#define DPLL_PIN_FREQUENCY_77_5_KHZ 77500 /** * enum dpll_pin_state - defines possible states of a pin, valid values for * DPLL_A_PIN_STATE attribute - * @DPLL_PIN_STATE_UNSPEC: unspecified value * @DPLL_PIN_STATE_CONNECTED: pin connected, active source of phase locked loop * @DPLL_PIN_STATE_DISCONNECTED: pin disconnected, not considered as a valid * source * @DPLL_PIN_STATE_SELECTABLE: pin enabled for automatic source selection */ enum dpll_pin_state { - DPLL_PIN_STATE_UNSPEC, - DPLL_PIN_STATE_CONNECTED, + DPLL_PIN_STATE_CONNECTED = 1, DPLL_PIN_STATE_DISCONNECTED, DPLL_PIN_STATE_SELECTABLE, @@ -145,15 +131,13 @@ enum dpll_pin_caps { /** * enum dpll_event - events of dpll generic netlink family - * @DPLL_EVENT_UNSPEC: invalid event type * @DPLL_EVENT_DEVICE_CREATE: dpll device created * @DPLL_EVENT_DEVICE_DELETE: dpll device deleted * @DPLL_EVENT_DEVICE_CHANGE: attribute of dpll device or pin changed, reason * is to be found with an attribute type (DPLL_A_*) received with the event */ enum dpll_event { - DPLL_EVENT_UNSPEC, - DPLL_EVENT_DEVICE_CREATE, + DPLL_EVENT_DEVICE_CREATE = 1, DPLL_EVENT_DEVICE_DELETE, DPLL_EVENT_DEVICE_CHANGE, }; @@ -189,8 +173,7 @@ enum dplla { }; enum { - DPLL_CMD_UNSPEC = 1, - DPLL_CMD_DEVICE_GET, + DPLL_CMD_DEVICE_GET = 1, DPLL_CMD_DEVICE_SET, DPLL_CMD_PIN_GET, DPLL_CMD_PIN_SET, From bd674f072f553f7065ac7ca0709cf0b9f0c9a2ac Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 14:27:06 +0200 Subject: [PATCH 10/93] dpll: core: remove unspec attributes Remove unspec attributes after removing from dpll netlink spec. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 4 ++-- drivers/dpll/dpll_netlink.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 8a2370740026..c325dd401166 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -451,7 +451,7 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, if (WARN_ON(!ops || !owner)) return -EINVAL; - if (WARN_ON(type <= DPLL_TYPE_UNSPEC || type > DPLL_TYPE_MAX)) + if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX)) return -EINVAL; mutex_lock(&dpll_xa_lock); @@ -559,7 +559,7 @@ dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, ret = -ENOMEM; goto err; } - if (WARN_ON(prop->type <= DPLL_PIN_TYPE_UNSPEC || + if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || prop->type > DPLL_PIN_TYPE_MAX)) { ret = -EINVAL; goto err; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 734b6776b07c..82bc484b02e2 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -353,7 +353,7 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, ret = dpll_msg_add_mode(msg, dpll, extack); if (ret) return ret; - for (mode = DPLL_MODE_UNSPEC + 1; mode <= DPLL_MODE_MAX; mode++) + for (mode = DPLL_MODE_MANUAL; mode <= DPLL_MODE_MAX; mode++) if (test_bit(mode, &dpll->mode_supported_mask)) if (nla_put_s32(msg, DPLL_A_MODE_SUPPORTED, mode)) return -EMSGSIZE; @@ -511,7 +511,7 @@ static int dpll_pin_set_from_nlattr(struct dpll_device *dpll, struct dpll_pin *pin, struct genl_info *info) { - enum dpll_pin_state state = DPLL_PIN_STATE_UNSPEC; + enum dpll_pin_state state = 0; bool parent_present = false; int rem, ret = -EINVAL; struct nlattr *a; @@ -546,7 +546,7 @@ dpll_pin_set_from_nlattr(struct dpll_device *dpll, break; } } - if (state != DPLL_PIN_STATE_UNSPEC) { + if (state) { if (!parent_present) { ret = dpll_pin_state_set(dpll, pin, state, info->extack); From 7d3793867c665ff6f1c63e3fea8cfa9ba7cc87ee Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 14:28:53 +0200 Subject: [PATCH 11/93] ice: dpll: remove unspec attributes Remove unspec attributes after removing from dpll netlink spec. Fixes: 6348a829aeb3 ("ice: add admin commands to access cgu configuration") Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 4568b0403cd7..129501467c71 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -275,13 +275,13 @@ static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_outputs[] = { }; static const struct ice_cgu_pin_desc ice_e823_si_cgu_inputs[] = { - { "NONE", SI_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, - { "NONE", SI_REF0N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", SI_REF0P, 0, 0 }, + { "NONE", SI_REF0N, 0, 0 }, { "SYNCE0_DP", SI_REF1P, DPLL_PIN_TYPE_MUX, 0 }, { "SYNCE0_DN", SI_REF1N, DPLL_PIN_TYPE_MUX, 0 }, { "EXT_CLK_SYNC", SI_REF2P, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, - { "NONE", SI_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", SI_REF2N, 0, 0 }, { "EXT_PPS_OUT", SI_REF3, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, { "INT_PPS_OUT", SI_REF4, DPLL_PIN_TYPE_EXT, @@ -299,16 +299,16 @@ static const struct ice_cgu_pin_desc ice_e823_si_cgu_outputs[] = { }; static const struct ice_cgu_pin_desc ice_e823_zl_cgu_inputs[] = { - { "NONE", ZL_REF0P, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", ZL_REF0P, 0, 0 }, { "INT_PPS_OUT", ZL_REF0N, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, { "SYNCE0_DP", ZL_REF1P, DPLL_PIN_TYPE_MUX, 0 }, { "SYNCE0_DN", ZL_REF1N, DPLL_PIN_TYPE_MUX, 0 }, - { "NONE", ZL_REF2P, DPLL_PIN_TYPE_UNSPEC, 0 }, - { "NONE", ZL_REF2N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", ZL_REF2P, 0, 0 }, + { "NONE", ZL_REF2N, 0, 0 }, { "EXT_CLK_SYNC", ZL_REF3P, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, - { "NONE", ZL_REF3N, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", ZL_REF3N, 0, 0 }, { "EXT_PPS_OUT", ZL_REF4P, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz }, { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0 }, @@ -323,7 +323,7 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = { { "1588-TIME_REF", ZL_OUT3, DPLL_PIN_TYPE_SYNCE_ETH_PORT, 0 }, { "CPK-TIME_SYNC", ZL_OUT4, DPLL_PIN_TYPE_EXT, ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common }, - { "NONE", ZL_OUT5, DPLL_PIN_TYPE_UNSPEC, 0 }, + { "NONE", ZL_OUT5, 0, 0 }, }; extern const struct From 70375195bfe919166facd5f2e4d36299ec761945 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 14:31:17 +0200 Subject: [PATCH 12/93] ice: dpll: remove unspec attributes Remove unspec attributes after removing from dpll netlink spec. Fixes: bff85d94a251 ("ice: implement dpll interface to control cgu") Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 3217fb36dd12..ef5ec3f4ab6e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -16,7 +16,7 @@ */ static const enum dpll_lock_status ice_dpll_status[__DPLL_LOCK_STATUS_MAX] = { - [ICE_CGU_STATE_INVALID] = DPLL_LOCK_STATUS_UNSPEC, + [ICE_CGU_STATE_INVALID] = 0, [ICE_CGU_STATE_FREERUN] = DPLL_LOCK_STATUS_UNLOCKED, [ICE_CGU_STATE_LOCKED] = DPLL_LOCK_STATUS_CALIBRATING, [ICE_CGU_STATE_LOCKED_HO_ACQ] = DPLL_LOCK_STATUS_LOCKED, From 58e19cbc891773a223b94fa4fbfc8f1e78630d73 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 11:55:42 +0200 Subject: [PATCH 13/93] dpll: spec: add 10 KHZ and 77,5 KHZ frequencies Add missing frequencies to the dpll ynl spec, so their defines are properly generated. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 8 ++++++++ include/uapi/linux/dpll.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 7b847038a511..e072a00710d0 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -122,6 +122,14 @@ definitions: type: const name: pin-frequency-1-hz value: 1 + - + type: const + name: pin-frequency-10-khz + value: 10000 + - + type: const + name: pin-frequency-77_5-khz + value: 77500 - type: const name: pin-frequency-10-mhz diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index b8a427cb4712..46d88e8fc4c3 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -100,6 +100,8 @@ enum dpll_pin_direction { }; #define DPLL_PIN_FREQUENCY_1_HZ 1 +#define DPLL_PIN_FREQUENCY_10_KHZ 10000 +#define DPLL_PIN_FREQUENCY_77_5_KHZ 77500 #define DPLL_PIN_FREQUENCY_10_MHZ 10000000 /** From ae82ad66aa35a89b8c8ec6aed2710ea3864a15a1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 8 May 2023 12:12:27 +0200 Subject: [PATCH 14/93] dpll: spec: fix documentation - remove "no holdover available" from freerun mode description - improve description of holdover lock-status - fix temperature typo Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 12 ++++++++---- include/uapi/linux/dpll.h | 7 +++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index e072a00710d0..3f13589c2c44 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -25,7 +25,7 @@ definitions: doc: dpll forced into holdover mode - name: freerun - doc: dpll driven on system clk, no holdover available + doc: dpll driven on system clk - name: nco doc: dpll driven by Numerically Controlled Oscillator @@ -52,8 +52,12 @@ definitions: - name: holdover doc: | - dpll is in holdover state - lost a valid lock or was forced by - selecting DPLL_MODE_HOLDOVER mode + dpll is in holdover state - lost a valid lock or was forced + by selecting DPLL_MODE_HOLDOVER mode (latter possible only + when dpll lock-state was already DPLL_LOCK_STATUS_LOCKED, + if dpll lock-state was not DPLL_LOCK_STATUS_LOCKED, the + dpll's lock-state shall remain DPLL_LOCK_STATUS_UNLOCKED + even if DPLL_MODE_HOLDOVER was requested) render-max: true - type: const @@ -63,7 +67,7 @@ definitions: temperature divider allowing userspace to calculate the temperature as float with single digit precision. Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of - tempearture value. + temperature value. Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of temperature value. - diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 46d88e8fc4c3..8c199278b900 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -16,7 +16,7 @@ * @DPLL_MODE_MANUAL: source can be only selected by sending a request to dpll * @DPLL_MODE_AUTOMATIC: highest prio, valid source, auto selected by dpll * @DPLL_MODE_HOLDOVER: dpll forced into holdover mode - * @DPLL_MODE_FREERUN: dpll driven on system clk, no holdover available + * @DPLL_MODE_FREERUN: dpll driven on system clk * @DPLL_MODE_NCO: dpll driven by Numerically Controlled Oscillator */ enum dpll_mode { @@ -38,7 +38,10 @@ enum dpll_mode { * @DPLL_LOCK_STATUS_CALIBRATING: dpll is trying to lock to a valid signal * @DPLL_LOCK_STATUS_LOCKED: dpll is locked * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or - * was forced by selecting DPLL_MODE_HOLDOVER mode + * was forced by selecting DPLL_MODE_HOLDOVER mode (latter possible only when + * dpll lock-state was already DPLL_LOCK_STATUS_LOCKED, if it was not, the + * dpll's lock-status will remain DPLL_LOCK_STATUS_UNLOCKED even if user + * requests DPLL_MODE_HOLDOVER) */ enum dpll_lock_status { DPLL_LOCK_STATUS_UNLOCKED = 1, From 78e4bd96bbbde2d281709425c5e0f6ac753f7bc7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 10:48:05 +0200 Subject: [PATCH 15/93] ice: dpll: do not store set flags ice_dpll_pin flags field is intended to store flags that were received after getting pin info from firmware, stop using it on set commands, as the flags of set commands can have different meaning and values. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index ef5ec3f4ab6e..b7edaa33c151 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -410,13 +410,17 @@ static int ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, const enum ice_dpll_pin_type pin_type) { - u8 flags = pin->flags[0]; + u8 flags = 0; int ret; if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { - flags |= ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN; + if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) + flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); } @@ -425,8 +429,6 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, "err:%d %s failed to enable %s pin:%u\n", ret, ice_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); - else - pin->flags[0] = flags; return ret; } @@ -447,14 +449,16 @@ static int ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, enum ice_dpll_pin_type pin_type) { - u8 flags = pin->flags[0]; + u8 flags = 0; int ret; if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { - flags &= ~(ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN); + if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) + flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { - flags &= ~(ICE_AQC_SET_CGU_OUT_CFG_OUT_EN); + if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) + flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); } if (ret) @@ -462,8 +466,6 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, "err:%d %s failed to disable %s pin:%u\n", ret, ice_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); - else - pin->flags[0] = flags; return ret; } From 134ad31069c3fa933615fac735082b72f941e08c Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 10:54:28 +0200 Subject: [PATCH 16/93] ice: dpll: fix use pin state Use ice_dpll_pin's 'state' field to provide state to the caller, as well as to check if state change requested shall be proceeded. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index b7edaa33c151..77783f16bbca 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1121,10 +1121,8 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) goto unlock; - if ((enable && !!(p->flags[hw_idx] & - ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN)) || - (!enable && !(p->flags[hw_idx] & - ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN))) { + if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) || + (!enable && p->state[hw_idx] == DPLL_PIN_STATE_DISCONNECTED)) { ret = -EINVAL; goto unlock; } @@ -1184,11 +1182,7 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, if (ret) goto unlock; - if (!!(p->flags[hw_idx] & - ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN)) - *state = DPLL_PIN_STATE_CONNECTED; - else - *state = DPLL_PIN_STATE_DISCONNECTED; + *state = p->state[hw_idx]; ret = 0; unlock: ice_dpll_cb_unlock(pf); From a8996c9deef68d87b5b2c87aa3f585864d121055 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 11:35:07 +0200 Subject: [PATCH 17/93] dpll: spec: remove values from subset attributes Remove attribute values of subset attributes, they are no longer needed as ynl lib was fixed. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 3f13589c2c44..70573d8d206d 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -287,7 +287,6 @@ attribute-sets: - name: id type: u32 - value: 2 - name: dev-name type: string @@ -320,7 +319,6 @@ attribute-sets: - name: pin-prio type: u32 - value: 19 - name: pin-state type: u8 @@ -332,12 +330,10 @@ attribute-sets: - name: pin-state type: u8 - value: 20 enum: pin-state - name: pin-parent-idx type: u32 - value: 22 - name: pin-rclk-device type: string @@ -348,7 +344,6 @@ attribute-sets: - name: pin-frequency-min type: u64 - value: 17 - name: pin-frequency-max type: u64 From 8e20d7f47de1c189628639470113e1c83f5d5234 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 17:00:24 +0200 Subject: [PATCH 18/93] dpll: spec: reorder dpll attributes Move device 'nest' to the end of the dpll netlink attributes. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 12 ++++++------ include/uapi/linux/dpll.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 70573d8d206d..c260e5653b8a 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -193,15 +193,10 @@ attribute-sets: name: dpll enum-name: dplla attributes: - - - name: device - type: nest - value: 1 - multi-attr: true - nested-attributes: device - name: id type: u32 + value: 1 - name: dev-name type: string @@ -280,6 +275,11 @@ attribute-sets: - name: pin-dpll-caps type: u32 + - + name: device + type: nest + multi-attr: true + nested-attributes: device - name: device subset-of: dpll diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 8c199278b900..6ebe7fb782c6 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -148,8 +148,7 @@ enum dpll_event { }; enum dplla { - DPLL_A_DEVICE = 1, - DPLL_A_ID, + DPLL_A_ID = 1, DPLL_A_DEV_NAME, DPLL_A_BUS_NAME, DPLL_A_MODE, @@ -172,6 +171,7 @@ enum dplla { DPLL_A_PIN_PARENT_IDX, DPLL_A_PIN_RCLK_DEVICE, DPLL_A_PIN_DPLL_CAPS, + DPLL_A_DEVICE, __DPLL_A_MAX, DPLL_A_MAX = (__DPLL_A_MAX - 1) From 30d851300318136c8771e78f494bbf76bc42278e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 17:56:30 +0200 Subject: [PATCH 19/93] dpll: spec: fix device nested attribute 'device' nested attribute shall be used only for receiving data from pin-get do/dump commands. Use it this way and define list of expected list of attributes for device-get which are not nested. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 79 +++++++++++---------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index c260e5653b8a..64c21587622b 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -280,49 +280,6 @@ attribute-sets: type: nest multi-attr: true nested-attributes: device - - - name: device - subset-of: dpll - attributes: - - - name: id - type: u32 - - - name: dev-name - type: string - - - name: bus-name - type: string - - - name: mode - type: u8 - enum: mode - - - name: mode-supported - type: u8 - enum: mode - multi-attr: true - - - name: lock-status - type: u8 - enum: lock-status - - - name: temp - type: s32 - - - name: clock-id - type: u64 - - - name: type - type: u8 - enum: type - - - name: pin-prio - type: u32 - - - name: pin-state - type: u8 - enum: pin-state - name: pin-parent subset-of: dpll @@ -347,6 +304,26 @@ attribute-sets: - name: pin-frequency-max type: u64 + - + name: device + subset-of: dpll + attributes: + - + name: id + type: u32 + - + name: dev-name + type: string + - + name: bus-name + type: string + - + name: pin-prio + type: u32 + - + name: pin-state + type: u8 + enum: pin-state operations: list: @@ -366,16 +343,22 @@ operations: - id - bus-name - dev-name - reply: + reply: &dev-attrs attributes: - - device + - id + - dev-name + - bus-name + - mode + - mode-supported + - lock-status + - temp + - clock-id + - type dump: pre: dpll-pre-dumpit post: dpll-post-dumpit - reply: - attributes: - - device + reply: *dev-attrs - name: device-set From 41ba43f588a610d7646b6a589ea8b63d4792e615 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 18:16:53 +0200 Subject: [PATCH 20/93] dpll: docs: fix DPLL_MODE_MANUAL docs Previously the docs reffered to DPLL_MODE_FORCED mode, but its name was changed to DPLL_MODE_MANUAL, fix it. Signed-off-by: Arkadiusz Kubalewski --- Documentation/dpll.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/dpll.rst b/Documentation/dpll.rst index fba5bc027967..4e484b3862a2 100644 --- a/Documentation/dpll.rst +++ b/Documentation/dpll.rst @@ -261,7 +261,7 @@ Values for ``DPLL_A_LOCK_STATUS`` attribute: Values for ``DPLL_A_MODE`` attribute: =================== ================================================ - ``MODE_FORCED`` source pin is force-selected by setting pin + ``MODE_MANUAL`` source pin is manually selected by setting pin state to ``DPLL_PIN_STATE_CONNECTED`` on a dpll ``MODE_AUTOMATIC`` source pin is auto selected according to configured pin priorities and source signal From 06965d3731eb2467f233a73d48fa823b121f5fef Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 18:19:43 +0200 Subject: [PATCH 21/93] dpll: spec: temperature with 3 digit float precision Previously temperature could be supplied with one digit float precision, use divider value of 1000 instead of 10 and allow three digit float precision for users. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 4 ++-- include/uapi/linux/dpll.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 64c21587622b..a5518bf2a02d 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -62,10 +62,10 @@ definitions: - type: const name: temp-divider - value: 10 + value: 1000 doc: | temperature divider allowing userspace to calculate the - temperature as float with single digit precision. + temperature as float with three digit decimal precision. Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of temperature value. Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 6ebe7fb782c6..602aef57def7 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -53,7 +53,7 @@ enum dpll_lock_status { DPLL_LOCK_STATUS_MAX = (__DPLL_LOCK_STATUS_MAX - 1) }; -#define DPLL_TEMP_DIVIDER 10 +#define DPLL_TEMP_DIVIDER 1000 /** * enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute From 13ace3c7a3270be1a054f49594d727b53d820e47 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 10 May 2023 19:56:22 +0200 Subject: [PATCH 22/93] dpll: spec: remove enum from subset definition Enum in subset attribute definition is redundant and not used for anything in YNL spec, remove it. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index a5518bf2a02d..59c6833b438b 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -287,7 +287,6 @@ attribute-sets: - name: pin-state type: u8 - enum: pin-state - name: pin-parent-idx type: u32 @@ -323,7 +322,6 @@ attribute-sets: - name: pin-state type: u8 - enum: pin-state operations: list: From 54b07874222883ecc2f9cbb144baed164313e674 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 11 May 2023 13:50:43 +0200 Subject: [PATCH 23/93] dpll: spec: move pin-direction to pin-dpll tuple Previously it was possible to have different pin-direction returned to the user depending on which dpll was given as argument for pin-get cmd. If pin was registered with multiple dplls each could have reported different direction. I.e. driver exposes chained pins, where one pin is an input for one dpll and an output for second dpll. Fix it by enclosing pin-direction in the 'device' nested attribute. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 59c6833b438b..a219cf379d20 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -322,6 +322,9 @@ attribute-sets: - name: pin-state type: u8 + - + name: pin-direction + type: u8 operations: list: @@ -398,7 +401,6 @@ operations: - pin-idx - pin-label - pin-type - - pin-direction - pin-frequency - pin-frequency-supported - pin-parent From d3278b50251bcc2fd917ae5fc38bd64ac8c6ad1e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 11 May 2023 13:56:12 +0200 Subject: [PATCH 24/93] dpll: core: move pin-direction to pin-dpll tuple Previously it was possible to have different pin-direction returned to the user depending on which dpll was given as argument for pin-get cmd. If pin was registered with multiple dplls each could have reported different direction. I.e. driver exposes chained pins, where one pin is an input for one dpll and an output for second dpll. Fix it by enclosing pin-direction in the 'device' nested attribute. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 82bc484b02e2..069decfd3de1 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -253,6 +253,9 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_msg_add_pin_prio(msg, pin, ref, extack); if (ret && ret != -EOPNOTSUPP) goto nest_cancel; + ret = dpll_msg_add_pin_direction(msg, pin, ref, extack); + if (ret) + goto nest_cancel; nla_nest_end(msg, attr); } @@ -278,9 +281,6 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, return -EMSGSIZE; if (nla_put_u32(msg, DPLL_A_PIN_DPLL_CAPS, pin->prop.capabilities)) return -EMSGSIZE; - ret = dpll_msg_add_pin_direction(msg, pin, ref, extack); - if (ret) - return ret; ret = dpll_msg_add_pin_freq(msg, pin, ref, extack, true); if (ret && ret != -EOPNOTSUPP) return ret; From 702f3f455dc81235728f4b6bd55096f47610c8d0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 12 May 2023 10:51:13 +0200 Subject: [PATCH 25/93] ice: remove include of uapi header The header is already included in linux/dpll.h. Remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 77783f16bbca..6bba93e1190f 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -5,7 +5,6 @@ #include "ice_lib.h" #include "ice_trace.h" #include -#include #define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 #define ICE_DPLL_LOCK_TRIES 1000 From 4bc2ca0c44ff32be12cd4215409718bcfa3dfc2e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 12 May 2023 10:57:06 +0200 Subject: [PATCH 26/93] ice: remove redundant check against null arguments Caller shall take care of checking if arguments are valid, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 6bba93e1190f..67ffa6de905d 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -62,9 +62,6 @@ ice_find_pin_idx(struct ice_pf *pf, const struct dpll_pin *pin, struct ice_dpll_pin *pins; int pin_num, i; - if (!pin || !pf) - return ICE_DPLL_PIN_IDX_INVALID; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { pins = pf->dplls.inputs; pin_num = pf->dplls.num_inputs; From d7a707a5e4dcb2a5a0ddf9ae9cebb9858f5b0b4e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 12 May 2023 11:51:04 +0200 Subject: [PATCH 27/93] ice: propagate lock function return value to the caller Propagate error return value of netlink callback mutex lock function to the caller, a dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 61 +++++++++++++++-------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 67ffa6de905d..6d6f7c85ed53 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -234,8 +234,9 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, pin_type); if (!p) { NL_SET_ERR_MSG(extack, "pin not found"); @@ -327,8 +328,9 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, pin_type); if (!p) { NL_SET_ERR_MSG(extack, "pin not found"); @@ -611,11 +613,13 @@ static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, { struct ice_pf *pf = priv; struct ice_dpll *d; + int ret; if (!pf) return -EINVAL; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; d = ice_find_dpll(pf, dpll); if (!d) return -EFAULT; @@ -645,11 +649,13 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *priv, { struct ice_pf *pf = priv; struct ice_dpll *d; + int ret; if (!pf) return -EINVAL; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; d = ice_find_dpll(pf, dpll); ice_dpll_cb_unlock(pf); if (!d) @@ -679,12 +685,17 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, { struct ice_pf *pf = priv; struct ice_dpll *d; + int ret; if (!pf) return false; - - if (ice_dpll_cb_lock(pf)) + ret = ice_dpll_cb_lock(pf); + if (ret) { + NL_SET_ERR_MSG_FMT(extack, + "verifing dpll supported mode=%d failed, err=%d", + mode, ret); return false; + } d = ice_find_dpll(pf, dpll); ice_dpll_cb_unlock(pf); if (!d) @@ -723,8 +734,9 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, pin_type); if (!p) goto unlock; @@ -832,8 +844,9 @@ ice_dpll_pin_state_get(const struct dpll_device *dpll, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, pin_type); if (!p) { NL_SET_ERR_MSG(extack, "pin not found"); @@ -939,8 +952,9 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); if (!p) { NL_SET_ERR_MSG(extack, "pin not found"); @@ -994,8 +1008,9 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, return ret; } - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); if (!p) { NL_SET_ERR_MSG(extack, "pin not found"); @@ -1098,8 +1113,9 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); if (!p) { ret = -EFAULT; @@ -1159,8 +1175,9 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, if (!pf) return ret; - if (ice_dpll_cb_lock(pf)) - return -EBUSY; + ret = ice_dpll_cb_lock(pf); + if (ret) + return ret; p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); if (!p) goto unlock; From b26f9ff7e59fb0dd7cdd22d94bd84110850973f8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 12 May 2023 12:22:12 +0200 Subject: [PATCH 28/93] ice: fix use switch case instead of if Replace if statements with enum values to the switch case statements. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 109 ++++++++++++++-------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 6d6f7c85ed53..07cd08dcf07f 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -62,13 +62,16 @@ ice_find_pin_idx(struct ice_pf *pf, const struct dpll_pin *pin, struct ice_dpll_pin *pins; int pin_num, i; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: pins = pf->dplls.inputs; pin_num = pf->dplls.num_inputs; - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: pins = pf->dplls.outputs; pin_num = pf->dplls.num_outputs; - } else { + break; + default: return ICE_DPLL_PIN_IDX_INVALID; } @@ -137,22 +140,24 @@ static struct ice_dpll_pin { struct ice_dpll_pin *pins; - int pin_num, i; + int pin_num = 0, i; if (!pin || !pf) return NULL; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: pins = pf->dplls.inputs; pin_num = pf->dplls.num_inputs; - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: pins = pf->dplls.outputs; pin_num = pf->dplls.num_outputs; - } else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) { - if (pin == pf->dplls.rclk.pin) - return &pf->dplls.rclk; - } else { - return NULL; + break; + case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: + return &pf->dplls.rclk; + default: + break; } for (i = 0; i < pin_num; i++) @@ -179,21 +184,23 @@ static int ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, const enum ice_dpll_pin_type pin_type, const u32 freq) { + int ret = -EINVAL; u8 flags; - int ret; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: flags = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ; ret = ice_aq_set_input_pin_cfg(&pf->hw, pin->idx, flags, pin->flags[0], freq, 0); - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { - flags = pin->flags[0] | ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ; + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: + flags = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_FREQ; ret = ice_aq_set_output_pin_cfg(&pf->hw, pin->idx, flags, 0, freq, 0); - } else { - ret = -EINVAL; + break; + default: + break; } - if (ret) { dev_dbg(ice_pf_to_dev(pf), "err:%d %s failed to set pin freq:%u on pin:%u\n", @@ -408,19 +415,24 @@ static int ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, const enum ice_dpll_pin_type pin_type) { + int ret = -EINVAL; u8 flags = 0; - int ret; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN; ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); + break; + default: + break; } if (ret) dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), @@ -447,17 +459,22 @@ static int ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, enum ice_dpll_pin_type pin_type) { + int ret = -EINVAL; u8 flags = 0; - int ret; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN) flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN; ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0); + break; + default: + break; } if (ret) dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), @@ -486,9 +503,10 @@ int ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, const enum ice_dpll_pin_type pin_type) { - int ret; + int ret = -EINVAL; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL, NULL, &pin->flags[0], &pin->freq, NULL); @@ -514,7 +532,8 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, pin->state[pf->dplls.pps.dpll_idx] = DPLL_PIN_STATE_DISCONNECTED; } - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx, &pin->flags[0], NULL, &pin->freq, NULL); @@ -522,7 +541,8 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, pin->state[0] = DPLL_PIN_STATE_CONNECTED; else pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; - } else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) { + break; + case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; for (parent = 0; parent < pf->dplls.rclk.num_parents; @@ -540,6 +560,9 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, pin->state[parent] = DPLL_PIN_STATE_DISCONNECTED; } + break; + default: + break; } return ret; @@ -740,16 +763,21 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, p = ice_find_pin(pf, pin, pin_type); if (!p) goto unlock; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: if (state == DPLL_PIN_STATE_SELECTABLE) ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); else if (state == DPLL_PIN_STATE_DISCONNECTED) ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: if (state == DPLL_PIN_STATE_CONNECTED) ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); else if (state == DPLL_PIN_STATE_DISCONNECTED) ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); + break; + default: + break; } if (!ret) ret = ice_dpll_pin_state_update(pf, p, pin_type); @@ -1710,16 +1738,19 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) u8 freq_supp_num; bool input; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) { + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: pins = pf->dplls.inputs; num_pins = pf->dplls.num_inputs; input = true; - } else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) { + break; + case ICE_DPLL_PIN_TYPE_OUTPUT: pins = pf->dplls.outputs; num_pins = pf->dplls.num_outputs; input = false; - } else { - return -EINVAL; + break; + default: + return ret; } for (i = 0; i < num_pins; i++) { @@ -1788,14 +1819,16 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) static int ice_dpll_init_pins(struct ice_pf *pf, const enum ice_dpll_pin_type pin_type) { - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) + switch (pin_type) { + case ICE_DPLL_PIN_TYPE_SOURCE: return ice_dpll_init_direct_pins(pf, pin_type); - else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) + case ICE_DPLL_PIN_TYPE_OUTPUT: return ice_dpll_init_direct_pins(pf, pin_type); - else if (pin_type == ICE_DPLL_PIN_TYPE_RCLK_SOURCE) + case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: return ice_dpll_init_rclk_pin(pf); - else + default: return -EINVAL; + } } /** From 323c0e80cb05a2f57ade2de63d6613e71c32d254 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 12 May 2023 14:10:45 +0200 Subject: [PATCH 29/93] ice: fix dev_dbg to dev_err for error cases In case of runtime errors the dev_err macro shall be used for printing the traces. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 07cd08dcf07f..73efb3369794 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -202,7 +202,7 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, break; } if (ret) { - dev_dbg(ice_pf_to_dev(pf), + dev_err(ice_pf_to_dev(pf), "err:%d %s failed to set pin freq:%u on pin:%u\n", ret, ice_aq_str(pf->hw.adminq.sq_last_status), freq, pin->idx); @@ -435,7 +435,7 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, break; } if (ret) - dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), + dev_err(ice_pf_to_dev((struct ice_pf *)(hw->back)), "err:%d %s failed to enable %s pin:%u\n", ret, ice_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); @@ -477,7 +477,7 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, break; } if (ret) - dev_dbg(ice_pf_to_dev((struct ice_pf *)(hw->back)), + dev_err(ice_pf_to_dev((struct ice_pf *)(hw->back)), "err:%d %s failed to disable %s pin:%u\n", ret, ice_aq_str(hw->adminq.sq_last_status), pin_type_name[pin_type], pin->idx); @@ -609,7 +609,7 @@ ice_dpll_hw_source_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, ret = ice_aq_set_cgu_ref_prio(&pf->hw, dpll->dpll_idx, pin->idx, (u8)prio); if (ret) - dev_dbg(ice_pf_to_dev(pf), + dev_err(ice_pf_to_dev(pf), "err:%d %s failed to set pin prio:%u on pin:%u\n", ret, ice_aq_str(pf->hw.adminq.sq_last_status), prio, pin->idx); From 63ab2eb7e98ce47469d5407642f96b682e6e3d7e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Sun, 14 May 2023 21:52:13 +0200 Subject: [PATCH 30/93] ice: fix dpll/pin lookup on dpll subsytem callbacks Add pf structure pointer to ice_dpll and ice_dpll_pin structures. Use ice_dpll and ice_dpll_pin structure pointers as private data when registering within dpll subsystem. New private data does not need to perform any lookups to perform callback requests. Remove ice_pind_pin as it is unused. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 249 ++++++---------------- drivers/net/ethernet/intel/ice/ice_dpll.h | 4 + 2 files changed, 69 insertions(+), 184 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 73efb3369794..939bc365acfa 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -120,53 +120,6 @@ static void ice_dpll_cb_unlock(struct ice_pf *pf) mutex_unlock(&pf->dplls.lock); } -/** - * ice_find_pin - find ice_dpll_pin on a pf - * @pf: private board structure - * @pin: kernel's dpll_pin pointer to be searched for - * @pin_type: type of pins to be searched for - * - * Find and return internal ice pin info pointer holding data of given dpll - * subsystem pin pointer. - * - * Return: - * * valid 'struct ice_dpll_pin'-type pointer - if given 'pin' pointer was - * found in pf internal pin data. - * * NULL - if pin was not found. - */ -static struct ice_dpll_pin -*ice_find_pin(struct ice_pf *pf, const struct dpll_pin *pin, - enum ice_dpll_pin_type pin_type) - -{ - struct ice_dpll_pin *pins; - int pin_num = 0, i; - - if (!pin || !pf) - return NULL; - - switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: - pins = pf->dplls.inputs; - pin_num = pf->dplls.num_inputs; - break; - case ICE_DPLL_PIN_TYPE_OUTPUT: - pins = pf->dplls.outputs; - pin_num = pf->dplls.num_outputs; - break; - case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: - return &pf->dplls.rclk; - default: - break; - } - - for (i = 0; i < pin_num; i++) - if (pin == pins[i].pin) - return &pins[i]; - - return NULL; -} - /** * ice_dpll_pin_freq_set - set pin's frequency * @pf: private board structure @@ -206,11 +159,12 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, "err:%d %s failed to set pin freq:%u on pin:%u\n", ret, ice_aq_str(pf->hw.adminq.sq_last_status), freq, pin->idx); + return ret; } else { pin->freq = freq; } - return ret; + return 0; } /** @@ -235,8 +189,8 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { - struct ice_pf *pf = pin_priv; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -244,17 +198,10 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, pin_type); - if (!p) { - NL_SET_ERR_MSG(extack, "pin not found"); - goto unlock; - } - ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency); + ice_dpll_cb_unlock(pf); if (ret) NL_SET_ERR_MSG_FMT(extack, "freq not set, err:%d", ret); -unlock: - ice_dpll_cb_unlock(pf); return ret; } @@ -329,8 +276,8 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { - struct ice_pf *pf = pin_priv; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -338,17 +285,10 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, pin_type); - if (!p) { - NL_SET_ERR_MSG(extack, "pin not found"); - goto unlock; - } - *frequency = (u64)(p->freq); - ret = 0; -unlock: + *frequency = p->freq; ice_dpll_cb_unlock(pf); - return ret; + return 0; } /** @@ -634,23 +574,21 @@ static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, enum dpll_lock_status *status, struct netlink_ext_ack *extack) { - struct ice_pf *pf = priv; - struct ice_dpll *d; - int ret; + struct ice_dpll *d = priv; + struct ice_pf *pf = d->pf; + int ret = -EINVAL; if (!pf) - return -EINVAL; + return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; - d = ice_find_dpll(pf, dpll); - if (!d) - return -EFAULT; - dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pf:%p\n", __func__, dpll, pf); *status = ice_dpll_status[d->dpll_state]; ice_dpll_cb_unlock(pf); + dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pf:%p, ret:%d\n", __func__, + dpll, pf, ret); - return 0; + return ret; } /** @@ -670,19 +608,11 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *priv, enum dpll_mode *mode, struct netlink_ext_ack *extack) { - struct ice_pf *pf = priv; - struct ice_dpll *d; - int ret; + struct ice_dpll *d = priv; + struct ice_pf *pf = d->pf; if (!pf) return -EINVAL; - ret = ice_dpll_cb_lock(pf); - if (ret) - return ret; - d = ice_find_dpll(pf, dpll); - ice_dpll_cb_unlock(pf); - if (!d) - return -EFAULT; *mode = DPLL_MODE_AUTOMATIC; return 0; @@ -706,23 +636,11 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, const enum dpll_mode mode, struct netlink_ext_ack *extack) { - struct ice_pf *pf = priv; - struct ice_dpll *d; - int ret; + struct ice_dpll *d = priv; + struct ice_pf *pf = d->pf; if (!pf) return false; - ret = ice_dpll_cb_lock(pf); - if (ret) { - NL_SET_ERR_MSG_FMT(extack, - "verifing dpll supported mode=%d failed, err=%d", - mode, ret); - return false; - } - d = ice_find_dpll(pf, dpll); - ice_dpll_cb_unlock(pf); - if (!d) - return false; if (mode == DPLL_MODE_AUTOMATIC) return true; @@ -751,8 +669,8 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { - struct ice_pf *pf = pin_priv; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -760,9 +678,6 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, pin_type); - if (!p) - goto unlock; switch (pin_type) { case ICE_DPLL_PIN_TYPE_SOURCE: if (state == DPLL_PIN_STATE_SELECTABLE) @@ -781,7 +696,6 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, } if (!ret) ret = ice_dpll_pin_state_update(pf, p, pin_type); -unlock: ice_dpll_cb_unlock(pf); dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, p:%p pf:%p state: %d ret:%d\n", @@ -864,22 +778,16 @@ ice_dpll_pin_state_get(const struct dpll_device *dpll, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { - struct ice_pf *pf = pin_priv; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; struct ice_dpll *d; int ret = -EINVAL; if (!pf) return ret; - ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, pin_type); - if (!p) { - NL_SET_ERR_MSG(extack, "pin not found"); - goto unlock; - } d = ice_find_dpll(pf, dpll); if (!d) goto unlock; @@ -972,9 +880,9 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, void *dpll_priv, u32 *prio, struct netlink_ext_ack *extack) { - struct ice_pf *pf = pin_priv; - struct ice_dpll *d = NULL; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -983,24 +891,12 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); - if (!p) { - NL_SET_ERR_MSG(extack, "pin not found"); - goto unlock; - } - d = ice_find_dpll(pf, dpll); - if (!d) { - NL_SET_ERR_MSG(extack, "dpll not found"); - goto unlock; - } *prio = d->input_prio[p->idx]; - ret = 0; -unlock: ice_dpll_cb_unlock(pf); dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, pf:%p ret:%d\n", __func__, dpll, pin, pf, ret); - return ret; + return 0; } /** @@ -1023,9 +919,9 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, void *dpll_priv, u32 prio, struct netlink_ext_ack *extack) { - struct ice_pf *pf = pin_priv; - struct ice_dpll *d = NULL; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_dpll *d = dpll_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -1039,20 +935,9 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_SOURCE); - if (!p) { - NL_SET_ERR_MSG(extack, "pin not found"); - goto unlock; - } - d = ice_find_dpll(pf, dpll); - if (!d) { - NL_SET_ERR_MSG(extack, "dpll not found"); - goto unlock; - } ret = ice_dpll_hw_source_prio_set(pf, d, p, prio); if (ret) NL_SET_ERR_MSG_FMT(extack, "unable to set prio: %d", ret); -unlock: ice_dpll_cb_unlock(pf); dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, pf:%p ret:%d\n", __func__, dpll, pin, pf, ret); @@ -1087,7 +972,7 @@ static int ice_dpll_source_direction(const struct dpll_pin *pin, } /** - * ice_dpll_source_direction - callback for get output pin direction + * ice_dpll_output_direction - callback for get output pin direction * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: registered dpll pointer @@ -1135,8 +1020,8 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; - struct ice_pf *pf = pin_priv; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -1144,11 +1029,6 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); - if (!p) { - ret = -EFAULT; - goto unlock; - } parent_idx = ice_find_pin_idx(pf, parent_pin, ICE_DPLL_PIN_TYPE_SOURCE); if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) { @@ -1196,9 +1076,9 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, enum dpll_pin_state *state, struct netlink_ext_ack *extack) { - struct ice_pf *pf = pin_priv; u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; - struct ice_dpll_pin *p; + struct ice_dpll_pin *p = pin_priv; + struct ice_pf *pf = p->pf; int ret = -EFAULT; if (!pf) @@ -1206,9 +1086,6 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - p = ice_find_pin(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); - if (!p) - goto unlock; parent_idx = ice_find_pin_idx(pf, parent_pin, ICE_DPLL_PIN_TYPE_SOURCE); if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) @@ -1299,7 +1176,7 @@ ice_dpll_release_rclk_pin(struct ice_pf *pf) if (!parent) continue; dpll_pin_on_pin_unregister(parent, rclk->pin, - &ice_dpll_rclk_ops, pf); + &ice_dpll_rclk_ops, rclk); } dpll_pin_put(rclk->pin); rclk->pin = NULL; @@ -1330,9 +1207,9 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, if (p && !IS_ERR_OR_NULL(p->pin)) { if (cgu && dpll_eec) - dpll_pin_unregister(dpll_eec, p->pin, ops, pf); + dpll_pin_unregister(dpll_eec, p->pin, ops, p); if (cgu && dpll_pps) - dpll_pin_unregister(dpll_pps, p->pin, ops, pf); + dpll_pin_unregister(dpll_pps, p->pin, ops, p); dpll_pin_put(p->pin); p->pin = NULL; } @@ -1367,15 +1244,16 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) pins[i].pin = NULL; return -ENOMEM; } + pins[i].pf = pf; if (cgu) { ret = dpll_pin_register(pf->dplls.eec.dpll, pins[i].pin, - ops, pf, NULL); + ops, &pins[i], NULL); if (ret) return ret; ret = dpll_pin_register(pf->dplls.pps.dpll, pins[i].pin, - ops, pf, NULL); + ops, &pins[i], NULL); if (ret) return ret; } @@ -1391,12 +1269,13 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) pins[i].pin = NULL; return -ENOMEM; } + pins[i].pf = pf; ret = dpll_pin_register(pf->dplls.eec.dpll, pins[i].pin, - ops, pf, NULL); + ops, &pins[i], NULL); if (ret) return ret; ret = dpll_pin_register(pf->dplls.pps.dpll, pins[i].pin, - ops, pf, NULL); + ops, &pins[i], NULL); if (ret) return ret; } @@ -1409,12 +1288,13 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) return -ENOMEM; } ops = &ice_dpll_rclk_ops; + pf->dplls.rclk.pf = pf; for (i = 0; i < pf->dplls.rclk.num_parents; i++) { struct dpll_pin *parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, - ops, pf, dev); + ops, &pf->dplls.rclk, dev); if (ret) return ret; } @@ -1450,30 +1330,31 @@ static void ice_generate_clock_id(struct ice_pf *pf, u64 *clock_id) static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) { struct device *dev = ice_pf_to_dev(pf); + struct ice_dpll *de = &pf->dplls.eec; + struct ice_dpll *dp = &pf->dplls.pps; int ret = -ENOMEM; u64 clock_id; ice_generate_clock_id(pf, &clock_id); - pf->dplls.eec.dpll = dpll_device_get(clock_id, pf->dplls.eec.dpll_idx, - THIS_MODULE); - if (!pf->dplls.eec.dpll) { + de->dpll = dpll_device_get(clock_id, de->dpll_idx, THIS_MODULE); + if (!de->dpll) { dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (eec)\n"); return ret; } - pf->dplls.pps.dpll = dpll_device_get(clock_id, pf->dplls.pps.dpll_idx, - THIS_MODULE); - if (!pf->dplls.pps.dpll) { + de->pf = pf; + dp->dpll = dpll_device_get(clock_id, dp->dpll_idx, THIS_MODULE); + if (!dp->dpll) { dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (pps)\n"); goto put_eec; } - + dp->pf = pf; if (cgu) { - ret = dpll_device_register(pf->dplls.eec.dpll, DPLL_TYPE_EEC, - &ice_dpll_ops, pf, dev); + ret = dpll_device_register(de->dpll, DPLL_TYPE_EEC, + &ice_dpll_ops, de, dev); if (ret) goto put_pps; - ret = dpll_device_register(pf->dplls.pps.dpll, DPLL_TYPE_PPS, - &ice_dpll_ops, pf, dev); + ret = dpll_device_register(dp->dpll, DPLL_TYPE_PPS, + &ice_dpll_ops, dp, dev); if (ret) goto put_pps; } @@ -1481,11 +1362,11 @@ static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) return 0; put_pps: - dpll_device_put(pf->dplls.pps.dpll); - pf->dplls.pps.dpll = NULL; + dpll_device_put(dp->dpll); + dp->dpll = NULL; put_eec: - dpll_device_put(pf->dplls.eec.dpll); - pf->dplls.eec.dpll = NULL; + dpll_device_put(de->dpll); + de->dpll = NULL; return ret; } @@ -1672,7 +1553,7 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) if (dp->dpll) { mutex_lock(&pf->dplls.lock); if (cgu) - dpll_device_unregister(dp->dpll, &ice_dpll_ops, pf); + dpll_device_unregister(dp->dpll, &ice_dpll_ops, dp); dpll_device_put(dp->dpll); mutex_unlock(&pf->dplls.lock); dev_dbg(ice_pf_to_dev(pf), "PPS dpll removed\n"); @@ -1681,7 +1562,7 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) if (de->dpll) { mutex_lock(&pf->dplls.lock); if (cgu) - dpll_device_unregister(de->dpll, &ice_dpll_ops, pf); + dpll_device_unregister(de->dpll, &ice_dpll_ops, de); dpll_device_put(de->dpll); mutex_unlock(&pf->dplls.lock); dev_dbg(ice_pf_to_dev(pf), "EEC dpll removed\n"); diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index aad48b9910b7..feaec98506e3 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -10,6 +10,7 @@ #define ICE_DPLL_RCLK_NUM_MAX 4 /** ice_dpll_pin - store info about pins * @pin: dpll pin structure + * @pf: pointer to pf, which has registered the dpll_pin * @flags: pin flags returned from HW * @idx: ice pin private idx * @state: state of a pin @@ -21,6 +22,7 @@ */ struct ice_dpll_pin { struct dpll_pin *pin; + struct ice_pf *pf; u8 idx; u8 num_parents; u8 parent_idx[ICE_DPLL_RCLK_NUM_MAX]; @@ -32,6 +34,7 @@ struct ice_dpll_pin { /** ice_dpll - store info required for DPLL control * @dpll: pointer to dpll dev + * @pf: pointer to pf, which has registered the dpll_device * @dpll_idx: index of dpll on the NIC * @source_idx: source currently selected * @prev_source_idx: source previously selected @@ -46,6 +49,7 @@ struct ice_dpll_pin { */ struct ice_dpll { struct dpll_device *dpll; + struct ice_pf *pf; int dpll_idx; u8 source_idx; u8 prev_source_idx; From 49157fee2d4c645485da7d4d2b75d10b60e690ff Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Sun, 14 May 2023 23:52:45 +0200 Subject: [PATCH 31/93] ice: fix extack of dpll subsystem callbacks Fixes to dpll subsystem netlink callback extack. Remove return values as they are already propagated. Add info with priority range in case requested priority is out of range. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 939bc365acfa..b63fd343aeae 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -201,7 +201,7 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency); ice_dpll_cb_unlock(pf); if (ret) - NL_SET_ERR_MSG_FMT(extack, "freq not set, err:%d", ret); + NL_SET_ERR_MSG(extack, "frequency was not set"); return ret; } @@ -928,7 +928,8 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, return ret; if (prio > ICE_DPLL_PRIO_MAX) { - NL_SET_ERR_MSG(extack, "prio out of range"); + NL_SET_ERR_MSG_FMT(extack, "prio out of supported range 0-%d", + ICE_DPLL_PRIO_MAX); return ret; } @@ -937,7 +938,7 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, return ret; ret = ice_dpll_hw_source_prio_set(pf, d, p, prio); if (ret) - NL_SET_ERR_MSG_FMT(extack, "unable to set prio: %d", ret); + NL_SET_ERR_MSG_FMT(extack, "unable to set prio: %u", prio); ice_dpll_cb_unlock(pf); dev_dbg(ice_pf_to_dev(pf), "%s: dpll:%p, pin:%p, pf:%p ret:%d\n", __func__, dpll, pin, pf, ret); From 5246a2ebf54f44926784b63eb86ce3e8c1dfa95d Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 00:10:14 +0200 Subject: [PATCH 32/93] ice: remove double negation and variable cast Double negation and a cast are not needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index b63fd343aeae..ef008359c682 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -226,7 +226,7 @@ ice_dpll_source_frequency_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 frequency, struct netlink_ext_ack *extack) { - return ice_dpll_frequency_set(pin, pin_priv, dpll, (u32)frequency, extack, + return ice_dpll_frequency_set(pin, pin_priv, dpll, frequency, extack, ICE_DPLL_PIN_TYPE_SOURCE); } @@ -450,7 +450,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL, NULL, &pin->flags[0], &pin->freq, NULL); - if (!!(ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0])) { + if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) { if (pin->pin) { pin->state[pf->dplls.eec.dpll_idx] = pin->pin == pf->dplls.eec.active_source ? @@ -477,7 +477,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx, &pin->flags[0], NULL, &pin->freq, NULL); - if (!!(ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0])) + if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) pin->state[0] = DPLL_PIN_STATE_CONNECTED; else pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; @@ -493,8 +493,8 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, &pin->freq); if (ret) return ret; - if (!!(ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN & - pin->flags[parent])) + if (ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN & + pin->flags[parent]) pin->state[parent] = DPLL_PIN_STATE_CONNECTED; else pin->state[parent] = From 9331b249ba6afd04af661af44c5d2295b3528ba8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 00:35:27 +0200 Subject: [PATCH 33/93] ice: simplify ice_dpll_pin_state_set function Decide expected state before calling the ice_dpll_pin_state_set function, which simplifies the code. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 44 ++++++++++------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index ef008359c682..b431cfb61e89 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -665,7 +665,7 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, static int ice_dpll_pin_state_set(const struct dpll_device *dpll, const struct dpll_pin *pin, void *pin_priv, - const enum dpll_pin_state state, + bool enable, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { @@ -678,28 +678,17 @@ ice_dpll_pin_state_set(const struct dpll_device *dpll, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: - if (state == DPLL_PIN_STATE_SELECTABLE) - ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); - else if (state == DPLL_PIN_STATE_DISCONNECTED) - ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); - break; - case ICE_DPLL_PIN_TYPE_OUTPUT: - if (state == DPLL_PIN_STATE_CONNECTED) - ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); - else if (state == DPLL_PIN_STATE_DISCONNECTED) - ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); - break; - default: - break; - } + if (enable) + ret = ice_dpll_pin_enable(&pf->hw, p, pin_type); + else + ret = ice_dpll_pin_disable(&pf->hw, p, pin_type); if (!ret) ret = ice_dpll_pin_state_update(pf, p, pin_type); ice_dpll_cb_unlock(pf); - dev_dbg(ice_pf_to_dev(pf), - "%s: dpll:%p, pin:%p, p:%p pf:%p state: %d ret:%d\n", - __func__, dpll, pin, p, pf, state, ret); + if (ret) + dev_err(ice_pf_to_dev(pf), + "%s: dpll:%p, pin:%p, p:%p pf:%p enable:%d ret:%d\n", + __func__, dpll, pin, p, pf, enable, ret); return ret; } @@ -726,7 +715,9 @@ static int ice_dpll_output_state_set(const struct dpll_pin *pin, const enum dpll_pin_state state, struct netlink_ext_ack *extack) { - return ice_dpll_pin_state_set(dpll, pin, pin_priv, state, extack, + bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; + + return ice_dpll_pin_state_set(dpll, pin, pin_priv, enable, extack, ICE_DPLL_PIN_TYPE_OUTPUT); } @@ -752,7 +743,9 @@ static int ice_dpll_source_state_set(const struct dpll_pin *pin, const enum dpll_pin_state state, struct netlink_ext_ack *extack) { - return ice_dpll_pin_state_set(dpll, pin, pin_priv, state, extack, + bool enable = state == DPLL_PIN_STATE_SELECTABLE ? true : false; + + return ice_dpll_pin_state_set(dpll, pin, pin_priv, enable, extack, ICE_DPLL_PIN_TYPE_SOURCE); } @@ -801,9 +794,10 @@ ice_dpll_pin_state_get(const struct dpll_device *dpll, ret = 0; unlock: ice_dpll_cb_unlock(pf); - dev_dbg(ice_pf_to_dev(pf), - "%s: dpll:%p, pin:%p, pf:%p state: %d ret:%d\n", - __func__, dpll, pin, pf, *state, ret); + if (ret) + dev_err(ice_pf_to_dev(pf), + "%s: dpll:%p, pin:%p, pf:%p state: %d ret:%d\n", + __func__, dpll, pin, pf, *state, ret); return ret; } From df6b9e328053fcfe40f49a97e3ae7126f620092f Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 11:59:45 +0200 Subject: [PATCH 34/93] dpll: core: pass parent_priv on state_on_pin_ Pass parent's priv data pointer when invoked callbacks are related to the pin on pin relation. This simplifies implementation on driver implementing a callback as it has direct access to the parent priv, it does not have to look for correct parent pin in its internal structures anymore. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 17 +++++++++++------ include/linux/dpll.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 069decfd3de1..453fc07622b1 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -189,6 +189,7 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, const struct dpll_pin *pin, static int dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, + struct dpll_pin_ref *dpll_ref, struct netlink_ext_ack *extack) { enum dpll_pin_state state; @@ -200,14 +201,15 @@ dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, xa_for_each(&pin->parent_refs, index, ref) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + void *parent_priv; ppin = ref->pin; - + parent_priv = dpll_pin_on_dpll_priv(dpll_ref->dpll, ppin); if (WARN_ON(!ops->state_on_pin_get)) return -EFAULT; ret = ops->state_on_pin_get(pin, dpll_pin_on_pin_priv(ppin, pin), - ppin, &state, extack); + ppin, parent_priv, &state, extack); if (ret) return -EFAULT; nest = nla_nest_start(msg, DPLL_A_PIN_PARENT); @@ -322,7 +324,7 @@ __dpll_cmd_pin_dump_one(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_cmd_pin_fill_details(msg, pin, ref, extack); if (ret) return ret; - ret = dpll_msg_add_pin_parents(msg, pin, extack); + ret = dpll_msg_add_pin_parents(msg, pin, ref, extack); if (ret) return ret; if (!xa_empty(&pin->dpll_refs)) { @@ -426,7 +428,9 @@ dpll_pin_on_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, if (ops->state_on_pin_set(pin_ref->pin, dpll_pin_on_pin_priv(parent_ref->pin, pin_ref->pin), - parent_ref->pin, state, extack)) + parent_ref->pin, + dpll_pin_on_dpll_priv(dpll, parent_ref->pin), + state, extack)) return -EFAULT; dpll_pin_parent_notify(dpll, pin_ref->pin, parent_ref->pin, DPLL_A_PIN_STATE); @@ -846,8 +850,9 @@ dpll_event_device_change(struct sk_buff *msg, struct dpll_device *dpll, break; case DPLL_A_PIN_STATE: if (parent) { - const struct dpll_pin_ops *ops; + void *parent_priv = dpll_pin_on_dpll_priv(dpll, parent); void *priv = dpll_pin_on_pin_priv(parent, pin); + const struct dpll_pin_ops *ops; ref = xa_load(&pin->parent_refs, parent->pin_idx); if (!ref) @@ -856,7 +861,7 @@ dpll_event_device_change(struct sk_buff *msg, struct dpll_device *dpll, if (!ops->state_on_pin_get) return -EOPNOTSUPP; ret = ops->state_on_pin_get(pin, priv, parent, - &state, NULL); + parent_priv, &state, NULL); if (ret) return ret; if (nla_put_u32(msg, DPLL_A_PIN_PARENT_IDX, diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 5945bb456794..93b59b13ac9d 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -52,6 +52,7 @@ struct dpll_pin_ops { struct netlink_ext_ack *extack); int (*state_on_pin_get)(const struct dpll_pin *pin, void *pin_priv, const struct dpll_pin *parent_pin, + void *parent_pin_priv, enum dpll_pin_state *state, struct netlink_ext_ack *extack); int (*state_on_dpll_get)(const struct dpll_pin *pin, void *pin_priv, @@ -60,6 +61,7 @@ struct dpll_pin_ops { struct netlink_ext_ack *extack); int (*state_on_pin_set)(const struct dpll_pin *pin, void *pin_priv, const struct dpll_pin *parent_pin, + void *parent_pin_priv, const enum dpll_pin_state state, struct netlink_ext_ack *extack); int (*state_on_dpll_set)(const struct dpll_pin *pin, void *pin_priv, From f95bb9280e49a5d38fa94b399ff16a9c78b0c8fd Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 12:05:15 +0200 Subject: [PATCH 35/93] ice: pass parent_priv on state_on_pin_ Implement changes on state_on_pin_ in ice driver. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 74 ++++------------------- 1 file changed, 13 insertions(+), 61 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index b431cfb61e89..9604f54dbbbc 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -41,47 +41,6 @@ static const char * const pin_type_name[] = { [ICE_DPLL_PIN_TYPE_RCLK_SOURCE] = "rclk-source", }; -/** - * ice_find_pin_idx - find ice_dpll_pin index on a pf - * @pf: private board structure - * @pin: kernel's dpll_pin pointer to be searched for - * @pin_type: type of pins to be searched for - * - * Find and return internal ice pin index of a searched dpll subsystem - * pin pointer. - * - * Return: - * * valid index for a given pin & pin type found on pf internal dpll struct - * * ICE_DPLL_PIN_IDX_INVALID - if pin was not found. - */ -static u32 -ice_find_pin_idx(struct ice_pf *pf, const struct dpll_pin *pin, - enum ice_dpll_pin_type pin_type) - -{ - struct ice_dpll_pin *pins; - int pin_num, i; - - switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: - pins = pf->dplls.inputs; - pin_num = pf->dplls.num_inputs; - break; - case ICE_DPLL_PIN_TYPE_OUTPUT: - pins = pf->dplls.outputs; - pin_num = pf->dplls.num_outputs; - break; - default: - return ICE_DPLL_PIN_IDX_INVALID; - } - - for (i = 0; i < pin_num; i++) - if (pin == pins[i].pin) - return i; - - return ICE_DPLL_PIN_IDX_INVALID; -} - /** * ice_dpll_cb_lock - lock dplls mutex in callback context * @pf: private board structure @@ -1010,12 +969,13 @@ static int ice_dpll_output_direction(const struct dpll_pin *pin, static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_pin *parent_pin, + void *parent_pin_priv, const enum dpll_pin_state state, struct netlink_ext_ack *extack) { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; - u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; - struct ice_dpll_pin *p = pin_priv; + struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; + u32 hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; struct ice_pf *pf = p->pf; int ret = -EINVAL; @@ -1024,14 +984,8 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - parent_idx = ice_find_pin_idx(pf, parent_pin, - ICE_DPLL_PIN_TYPE_SOURCE); - if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) { - ret = -EFAULT; - goto unlock; - } for (i = 0; i < pf->dplls.rclk.num_parents; i++) - if (pf->dplls.rclk.parent_idx[i] == parent_idx) + if (pf->dplls.rclk.parent_idx[i] == parent->idx) hw_idx = i; if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) goto unlock; @@ -1045,8 +999,8 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, &p->freq); unlock: ice_dpll_cb_unlock(pf); - dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p ret:%d\n", - __func__, parent_pin, pin, pf, ret); + dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p enable:%d ret:%d\n", + __func__, parent_pin, pin, pf, enable, ret); return ret; } @@ -1068,11 +1022,12 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_pin *parent_pin, + void *parent_pin_priv, enum dpll_pin_state *state, struct netlink_ext_ack *extack) { - u32 parent_idx, hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; - struct ice_dpll_pin *p = pin_priv; + struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; + u32 hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; struct ice_pf *pf = p->pf; int ret = -EFAULT; @@ -1081,12 +1036,8 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - parent_idx = ice_find_pin_idx(pf, parent_pin, - ICE_DPLL_PIN_TYPE_SOURCE); - if (parent_idx == ICE_DPLL_PIN_IDX_INVALID) - goto unlock; for (i = 0; i < pf->dplls.rclk.num_parents; i++) - if (pf->dplls.rclk.parent_idx[i] == parent_idx) + if (pf->dplls.rclk.parent_idx[i] == parent->idx) hw_idx = i; if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) goto unlock; @@ -1099,8 +1050,9 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, ret = 0; unlock: ice_dpll_cb_unlock(pf); - dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p ret:%d\n", - __func__, parent_pin, pin, pf, ret); + dev_dbg(ice_pf_to_dev(pf), + "%s: parent:%p, pin:%p, pf:%p state:%u ret:%d\n", + __func__, parent_pin, pin, pf, *state, ret); return ret; } From 08ef5101f2b1226c29f0b629da1bb99e25561e3e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 13:14:41 +0200 Subject: [PATCH 36/93] ice: remove parent hw_idx lookup Instead of parent hw_idx lookup use an equation to obtain it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 30 ++++++++++------------- drivers/net/ethernet/intel/ice/ice_dpll.h | 3 ++- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 9604f54dbbbc..6e843ceb8973 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -975,19 +975,17 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; - u32 hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; struct ice_pf *pf = p->pf; int ret = -EINVAL; + u32 hw_idx; if (!pf) return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; - for (i = 0; i < pf->dplls.rclk.num_parents; i++) - if (pf->dplls.rclk.parent_idx[i] == parent->idx) - hw_idx = i; - if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) + hw_idx = parent->idx - pf->dplls.base_rclk_idx; + if (hw_idx >= pf->dplls.num_inputs) goto unlock; if ((enable && p->state[hw_idx] == DPLL_PIN_STATE_CONNECTED) || @@ -999,8 +997,9 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, &p->freq); unlock: ice_dpll_cb_unlock(pf); - dev_dbg(ice_pf_to_dev(pf), "%s: parent:%p, pin:%p, pf:%p enable:%d ret:%d\n", - __func__, parent_pin, pin, pf, enable, ret); + dev_dbg(ice_pf_to_dev(pf), + "%s: parent:%p, pin:%p, pf:%p hw_idx:%u enable:%d ret:%d\n", + __func__, parent_pin, pin, pf, hw_idx, enable, ret); return ret; } @@ -1027,19 +1026,17 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, struct netlink_ext_ack *extack) { struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; - u32 hw_idx = ICE_DPLL_PIN_IDX_INVALID, i; struct ice_pf *pf = p->pf; int ret = -EFAULT; + u32 hw_idx; if (!pf) return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; - for (i = 0; i < pf->dplls.rclk.num_parents; i++) - if (pf->dplls.rclk.parent_idx[i] == parent->idx) - hw_idx = i; - if (hw_idx == ICE_DPLL_PIN_IDX_INVALID) + hw_idx = parent->idx - pf->dplls.base_rclk_idx; + if (hw_idx >= pf->dplls.num_inputs) goto unlock; ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); @@ -1051,8 +1048,8 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, unlock: ice_dpll_cb_unlock(pf); dev_dbg(ice_pf_to_dev(pf), - "%s: parent:%p, pin:%p, pf:%p state:%u ret:%d\n", - __func__, parent_pin, pin, pf, *state, ret); + "%s: parent:%p, pin:%p, pf:%p hw_idx:%u state:%u ret:%d\n", + __func__, parent_pin, pin, pf, hw_idx, *state, ret); return ret; } @@ -1678,7 +1675,6 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) struct ice_dplls *d = &pf->dplls; struct ice_hw *hw = &pf->hw; int ret, alloc_size, i; - u8 base_rclk_idx; ice_generate_clock_id(pf, &d->clock_id); ret = ice_aq_get_cgu_abilities(hw, &abilities); @@ -1723,12 +1719,12 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) goto release_info; } - ret = ice_get_cgu_rclk_pin_info(&pf->hw, &base_rclk_idx, + ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, &pf->dplls.rclk.num_parents); if (ret) return ret; for (i = 0; i < pf->dplls.rclk.num_parents; i++) - pf->dplls.rclk.parent_idx[i] = base_rclk_idx + i; + pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); if (ret) return ret; diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index feaec98506e3..1f6b1e0268e4 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -74,8 +74,9 @@ struct ice_dpll { * @rclk: recovered pins pointer * @num_inputs: number of input pins available on dpll * @num_outputs: number of output pins available on dpll - * @num_rclk: number of recovered clock pins available on dpll * @cgu_state_acq_err_num: number of errors returned during periodic work + * @base_rclk_idx: idx of first pin used for clock revocery pins + * @clock_id: clock_id of dplls */ struct ice_dplls { struct kthread_worker *kworker; From 6e9d401dc578a98ee266ab2232184ee0ee6a7572 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 13:29:40 +0200 Subject: [PATCH 37/93] ice: fix use const qualifier for dpll/dpll_pin ops Definition of callback arrays now const as expected. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 6e843ceb8973..4c4402ad9130 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1054,13 +1054,13 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, return ret; } -static struct dpll_pin_ops ice_dpll_rclk_ops = { +static const struct dpll_pin_ops ice_dpll_rclk_ops = { .state_on_pin_set = ice_dpll_rclk_state_on_pin_set, .state_on_pin_get = ice_dpll_rclk_state_on_pin_get, .direction_get = ice_dpll_source_direction, }; -static struct dpll_pin_ops ice_dpll_source_ops = { +static const struct dpll_pin_ops ice_dpll_source_ops = { .frequency_get = ice_dpll_source_frequency_get, .frequency_set = ice_dpll_source_frequency_set, .state_on_dpll_get = ice_dpll_source_state_get, @@ -1070,7 +1070,7 @@ static struct dpll_pin_ops ice_dpll_source_ops = { .direction_get = ice_dpll_source_direction, }; -static struct dpll_pin_ops ice_dpll_output_ops = { +static const struct dpll_pin_ops ice_dpll_output_ops = { .frequency_get = ice_dpll_output_frequency_get, .frequency_set = ice_dpll_output_frequency_set, .state_on_dpll_get = ice_dpll_output_state_get, @@ -1078,7 +1078,7 @@ static struct dpll_pin_ops ice_dpll_output_ops = { .direction_get = ice_dpll_output_direction, }; -static struct dpll_device_ops ice_dpll_ops = { +static const struct dpll_device_ops ice_dpll_ops = { .lock_status_get = ice_dpll_lock_status_get, .mode_get = ice_dpll_mode_get, .mode_supported = ice_dpll_mode_supported, @@ -1142,7 +1142,7 @@ ice_dpll_release_rclk_pin(struct ice_pf *pf) static void ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, struct dpll_device *dpll_pps, struct ice_dpll_pin *pins, - int count, struct dpll_pin_ops *ops, bool cgu) + int count, const struct dpll_pin_ops *ops, bool cgu) { int i; @@ -1174,8 +1174,8 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) { struct device *dev = ice_pf_to_dev(pf); + const struct dpll_pin_ops *ops; struct ice_dpll_pin *pins; - struct dpll_pin_ops *ops; u32 rclk_idx; int ret, i; From 53ce702976bc7cf546816017d5de010a7485a9f9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 14:10:24 +0200 Subject: [PATCH 38/93] ice: fix IS_ERR macros usage in ice_dpll Previously IS_ERR_OR_NULL was used worngly as the function cannot return NULL, use IS_ERR instead. In case of error, return original error value. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 53 +++++++++-------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 4c4402ad9130..a6969555ab8a 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1149,7 +1149,7 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, for (i = 0; i < count; i++) { struct ice_dpll_pin *p = &pins[i]; - if (p && !IS_ERR_OR_NULL(p->pin)) { + if (p && !IS_ERR(p->pin)) { if (cgu && dpll_eec) dpll_pin_unregister(dpll_eec, p->pin, ops, p); if (cgu && dpll_pps) @@ -1184,10 +1184,8 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) for (i = 0; i < pf->dplls.num_inputs; i++) { pins[i].pin = dpll_pin_get(pf->dplls.clock_id, i, THIS_MODULE, &pins[i].prop); - if (IS_ERR_OR_NULL(pins[i].pin)) { - pins[i].pin = NULL; - return -ENOMEM; - } + if (IS_ERR(pins[i].pin)) + return PTR_ERR(pins[i].pin); pins[i].pf = pf; if (cgu) { ret = dpll_pin_register(pf->dplls.eec.dpll, @@ -1209,10 +1207,8 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) pins[i].pin = dpll_pin_get(pf->dplls.clock_id, i + pf->dplls.num_inputs, THIS_MODULE, &pins[i].prop); - if (IS_ERR_OR_NULL(pins[i].pin)) { - pins[i].pin = NULL; - return -ENOMEM; - } + if (IS_ERR(pins[i].pin)) + return PTR_ERR(pins[i].pin); pins[i].pf = pf; ret = dpll_pin_register(pf->dplls.eec.dpll, pins[i].pin, ops, &pins[i], NULL); @@ -1227,10 +1223,8 @@ static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; pf->dplls.rclk.pin = dpll_pin_get(pf->dplls.clock_id, rclk_idx, THIS_MODULE, &pf->dplls.rclk.prop); - if (IS_ERR_OR_NULL(pf->dplls.rclk.pin)) { - pf->dplls.rclk.pin = NULL; - return -ENOMEM; - } + if (IS_ERR(pf->dplls.rclk.pin)) + return PTR_ERR(pf->dplls.rclk.pin); ops = &ice_dpll_rclk_ops; pf->dplls.rclk.pf = pf; for (i = 0; i < pf->dplls.rclk.num_parents; i++) { @@ -1281,38 +1275,33 @@ static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) ice_generate_clock_id(pf, &clock_id); de->dpll = dpll_device_get(clock_id, de->dpll_idx, THIS_MODULE); - if (!de->dpll) { - dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (eec)\n"); + if (IS_ERR(de->dpll)) { + ret = PTR_ERR(de->dpll); + dev_err(ice_pf_to_dev(pf), + "dpll_device_get failed (eec) err=%d\n", ret); return ret; } de->pf = pf; dp->dpll = dpll_device_get(clock_id, dp->dpll_idx, THIS_MODULE); - if (!dp->dpll) { - dev_err(ice_pf_to_dev(pf), "dpll_device_get failed (pps)\n"); - goto put_eec; + if (IS_ERR(dp->dpll)) { + ret = PTR_ERR(dp->dpll); + dev_err(ice_pf_to_dev(pf), + "dpll_device_get failed (pps) err=%d\n", ret); + return ret; } dp->pf = pf; if (cgu) { ret = dpll_device_register(de->dpll, DPLL_TYPE_EEC, &ice_dpll_ops, de, dev); if (ret) - goto put_pps; + return ret; ret = dpll_device_register(dp->dpll, DPLL_TYPE_PPS, &ice_dpll_ops, dp, dev); if (ret) - goto put_pps; + return ret; } return 0; - -put_pps: - dpll_device_put(dp->dpll); - dp->dpll = NULL; -put_eec: - dpll_device_put(de->dpll); - de->dpll = NULL; - - return ret; } /** @@ -1494,7 +1483,7 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) mutex_unlock(&pf->dplls.lock); } ice_dpll_release_info(pf); - if (dp->dpll) { + if (!IS_ERR(dp->dpll)) { mutex_lock(&pf->dplls.lock); if (cgu) dpll_device_unregister(dp->dpll, &ice_dpll_ops, dp); @@ -1503,7 +1492,7 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) dev_dbg(ice_pf_to_dev(pf), "PPS dpll removed\n"); } - if (de->dpll) { + if (!IS_ERR(de->dpll)) { mutex_lock(&pf->dplls.lock); if (cgu) dpll_device_unregister(de->dpll, &ice_dpll_ops, de); @@ -1515,7 +1504,7 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) if (cgu) { mutex_lock(&pf->dplls.lock); kthread_cancel_delayed_work_sync(&d->work); - if (d->kworker) { + if (!IS_ERR_OR_NULL(d->kworker)) { kthread_destroy_worker(d->kworker); d->kworker = NULL; dev_dbg(ice_pf_to_dev(pf), "DPLLs worker removed\n"); From d8cd3e2fa780e1ebaac0f6287762002a6ef60bde Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 15:42:48 +0200 Subject: [PATCH 39/93] ice: add notify previous source state change When source pin changes previous source state notification shall be also requested, request it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index a6969555ab8a..f1782a31f4d6 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1374,6 +1374,9 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) dpll_device_notify(d->dpll, DPLL_A_LOCK_STATUS); } if (d->prev_source != d->active_source) { + if (d->prev_source) + dpll_pin_notify(d->dpll, d->prev_source, + DPLL_A_PIN_STATE); d->prev_source = d->active_source; if (d->active_source) dpll_pin_notify(d->dpll, d->active_source, From ed4d8775ae74e37f5641502eb32fa9fa18c41b93 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 15:46:02 +0200 Subject: [PATCH 40/93] ice: fix mutex locking on releasing pins Simplify code by locking dpll subsystem once and releasing all the resources, instead of locking per each resource release. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index f1782a31f4d6..e7c16e70ea0e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1477,43 +1477,35 @@ static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) ice_dpll_release_rclk_pin(pf); ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->inputs, d->num_inputs, &ice_dpll_source_ops, cgu); - mutex_unlock(&pf->dplls.lock); if (cgu) { - mutex_lock(&pf->dplls.lock); ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->outputs, d->num_outputs, &ice_dpll_output_ops, cgu); - mutex_unlock(&pf->dplls.lock); } ice_dpll_release_info(pf); if (!IS_ERR(dp->dpll)) { - mutex_lock(&pf->dplls.lock); if (cgu) dpll_device_unregister(dp->dpll, &ice_dpll_ops, dp); dpll_device_put(dp->dpll); - mutex_unlock(&pf->dplls.lock); dev_dbg(ice_pf_to_dev(pf), "PPS dpll removed\n"); } if (!IS_ERR(de->dpll)) { - mutex_lock(&pf->dplls.lock); if (cgu) dpll_device_unregister(de->dpll, &ice_dpll_ops, de); dpll_device_put(de->dpll); - mutex_unlock(&pf->dplls.lock); dev_dbg(ice_pf_to_dev(pf), "EEC dpll removed\n"); } if (cgu) { - mutex_lock(&pf->dplls.lock); kthread_cancel_delayed_work_sync(&d->work); if (!IS_ERR_OR_NULL(d->kworker)) { kthread_destroy_worker(d->kworker); d->kworker = NULL; dev_dbg(ice_pf_to_dev(pf), "DPLLs worker removed\n"); } - mutex_unlock(&pf->dplls.lock); } + mutex_unlock(&pf->dplls.lock); } /** From 6ebe6b91a8c849bdaa0f758d98ff0d888e17ae5e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 15:50:22 +0200 Subject: [PATCH 41/93] ice: use '|=' instead of '+=' when modifing capabilities field Use proper way of setting bits for capabilities field. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index e7c16e70ea0e..4b3a450d746b 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1575,10 +1575,10 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) &dp->input_prio[i]); if (ret) return ret; - pins[i].prop.capabilities += + pins[i].prop.capabilities |= DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE; } - pins[i].prop.capabilities += DPLL_PIN_CAPS_STATE_CAN_CHANGE; + pins[i].prop.capabilities |= DPLL_PIN_CAPS_STATE_CAN_CHANGE; ret = ice_dpll_pin_state_update(pf, &pins[i], pin_type); if (ret) return ret; @@ -1608,7 +1608,7 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) pin->prop.label = dev_name(dev); pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; - pin->prop.capabilities += DPLL_PIN_CAPS_STATE_CAN_CHANGE; + pin->prop.capabilities |= DPLL_PIN_CAPS_STATE_CAN_CHANGE; return ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); From 14d6987aa57c5f3c79d62915e21529b26b214077 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 16:17:53 +0200 Subject: [PATCH 42/93] ice: rename ice_dpll_register_pins function Align function name with dpll counterpart (rename from ice_dpll_register_pins to ice_dpll_init_pins), similarly old ice_dpll_init_pins function renamed to ice_dpll_init_pins_info. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 4b3a450d746b..2d3a30a89db9 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1161,7 +1161,7 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, } /** - * ice_dpll_register_pins - register pins with a dpll + * ice_dpll_init_pins - init pins and register pins with a dplls * @pf: board private structure * @cgu: if cgu is present and controlled by this NIC * @@ -1171,7 +1171,7 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, * * 0 - success * * negative - error */ -static int ice_dpll_register_pins(struct ice_pf *pf, bool cgu) +static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) { struct device *dev = ice_pf_to_dev(pf); const struct dpll_pin_ops *ops; @@ -1615,7 +1615,7 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) } /** - * ice_dpll_init_pins - init pins wrapper + * ice_dpll_init_pins_info - init pins info wrapper * @pf: board private structure * @pin_type: type of pins being initialized * @@ -1625,8 +1625,9 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) * * 0 - success * * negative - init failure */ -static int ice_dpll_init_pins(struct ice_pf *pf, - const enum ice_dpll_pin_type pin_type) +static int +ice_dpll_init_pins_info(struct ice_pf *pf, + const enum ice_dpll_pin_type pin_type) { switch (pin_type) { case ICE_DPLL_PIN_TYPE_SOURCE: @@ -1688,7 +1689,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) if (!dp->input_prio) return -ENOMEM; - ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_SOURCE); + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_SOURCE); if (ret) goto release_info; @@ -1698,7 +1699,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) if (!d->outputs) goto release_info; - ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_OUTPUT); + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT); if (ret) goto release_info; } @@ -1709,7 +1710,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) return ret; for (i = 0; i < pf->dplls.rclk.num_parents; i++) pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; - ret = ice_dpll_init_pins(pf, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); if (ret) return ret; @@ -1754,7 +1755,7 @@ int ice_dpll_init(struct ice_pf *pf) err = ice_dpll_init_dplls(pf, cgu_present); if (err) goto release; - err = ice_dpll_register_pins(pf, cgu_present); + err = ice_dpll_init_pins(pf, cgu_present); if (err) goto release; set_bit(ICE_FLAG_DPLL, pf->flags); From 9265a6fb089bdf510b8ce0645b13b39633882537 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 15 May 2023 18:37:37 +0200 Subject: [PATCH 43/93] ice: simplify clock_id generation Change the clock_id function to return clock ID on the stack instead of using an output variable, in order to simplify the function. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 2d3a30a89db9..8aa46763ded1 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1243,14 +1243,15 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) /** * ice_generate_clock_id - generates unique clock_id for registering dpll. * @pf: board private structure - * @clock_id: holds generated clock_id * * Generates unique (per board) clock_id for allocation and search of dpll * devices in Linux dpll subsystem. + * + * Return: generated clock id for the board */ -static void ice_generate_clock_id(struct ice_pf *pf, u64 *clock_id) +static u64 ice_generate_clock_id(struct ice_pf *pf) { - *clock_id = pci_get_dsn(pf->pdev); + return pci_get_dsn(pf->pdev); } /** @@ -1273,7 +1274,7 @@ static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) int ret = -ENOMEM; u64 clock_id; - ice_generate_clock_id(pf, &clock_id); + clock_id = pf->dplls.clock_id; de->dpll = dpll_device_get(clock_id, de->dpll_idx, THIS_MODULE); if (IS_ERR(de->dpll)) { ret = PTR_ERR(de->dpll); @@ -1661,7 +1662,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) struct ice_hw *hw = &pf->hw; int ret, alloc_size, i; - ice_generate_clock_id(pf, &d->clock_id); + d->clock_id = ice_generate_clock_id(pf); ret = ice_aq_get_cgu_abilities(hw, &abilities); if (ret) { dev_err(ice_pf_to_dev(pf), From c7f8312f23e105407342cf191eabcac257314c16 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 22:10:35 +0200 Subject: [PATCH 44/93] dpll: spec: remove DPLL_MODE_NCO Remove the mode as it is not used by any of the in-kernel drivers implementing the dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 7 ++----- drivers/dpll/dpll_nl.c | 2 +- include/uapi/linux/dpll.h | 10 ++++------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index a219cf379d20..76094e1244b8 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -26,9 +26,6 @@ definitions: - name: freerun doc: dpll driven on system clk - - - name: nco - doc: dpll driven by Numerically Controlled Oscillator render-max: true - type: enum @@ -40,8 +37,8 @@ definitions: - name: unlocked doc: | - dpll was not yet locked to any valid source (or is in one of - modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) + dpll was not yet locked to any valid source (or is in mode: + DPLL_MODE_FREERUN) value: 1 - name: calibrating diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index 2f8643f401b0..e08f5aa4d856 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -22,7 +22,7 @@ static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_MODE + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_MODE] = NLA_POLICY_MAX(NLA_U8, 5), + [DPLL_A_MODE] = NLA_POLICY_MAX(NLA_U8, 4), }; /* DPLL_CMD_PIN_GET - do */ diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 602aef57def7..cd831a72ea65 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -17,14 +17,12 @@ * @DPLL_MODE_AUTOMATIC: highest prio, valid source, auto selected by dpll * @DPLL_MODE_HOLDOVER: dpll forced into holdover mode * @DPLL_MODE_FREERUN: dpll driven on system clk - * @DPLL_MODE_NCO: dpll driven by Numerically Controlled Oscillator */ enum dpll_mode { DPLL_MODE_MANUAL = 1, DPLL_MODE_AUTOMATIC, DPLL_MODE_HOLDOVER, DPLL_MODE_FREERUN, - DPLL_MODE_NCO, __DPLL_MODE_MAX, DPLL_MODE_MAX = (__DPLL_MODE_MAX - 1) @@ -34,14 +32,14 @@ enum dpll_mode { * enum dpll_lock_status - provides information of dpll device lock status, * valid values for DPLL_A_LOCK_STATUS attribute * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid source (or - * is in one of modes: DPLL_MODE_FREERUN, DPLL_MODE_NCO) + * is in mode: DPLL_MODE_FREERUN) * @DPLL_LOCK_STATUS_CALIBRATING: dpll is trying to lock to a valid signal * @DPLL_LOCK_STATUS_LOCKED: dpll is locked * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or * was forced by selecting DPLL_MODE_HOLDOVER mode (latter possible only when - * dpll lock-state was already DPLL_LOCK_STATUS_LOCKED, if it was not, the - * dpll's lock-status will remain DPLL_LOCK_STATUS_UNLOCKED even if user - * requests DPLL_MODE_HOLDOVER) + * dpll lock-state was already DPLL_LOCK_STATUS_LOCKED, if dpll lock-state + * was not DPLL_LOCK_STATUS_LOCKED, the dpll's lock-state shall remain + * DPLL_LOCK_STATUS_UNLOCKED even if DPLL_MODE_HOLDOVER was requested) */ enum dpll_lock_status { DPLL_LOCK_STATUS_UNLOCKED = 1, From b2bf6ccbbdfea265b31c4bfd0bd2cc2a809c44c4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 22:34:40 +0200 Subject: [PATCH 45/93] dpll: docs: remove DPLL_MODE_NCO Remove the mode as it is not used by any of the in-kernel drivers implementing the dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- Documentation/dpll.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/dpll.rst b/Documentation/dpll.rst index 4e484b3862a2..51e4cbef6ae1 100644 --- a/Documentation/dpll.rst +++ b/Documentation/dpll.rst @@ -269,8 +269,6 @@ Values for ``DPLL_A_MODE`` attribute: ``MODE_HOLDOVER`` force holdover mode of dpll ``MODE_FREERUN`` dpll device is driven by supplied system clock without holdover capabilities - ``MODE_NCO`` similar to FREERUN, with possibility to - numerically control frequency offset Values for ``DPLL_A_TYPE`` attribute: From 17fc436ce0bfce8706a825e2a74e936d3157aeb6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 22:52:06 +0200 Subject: [PATCH 46/93] dpll: spec: remove DPLL_LOCK_STATUS_CALIBRATING DPLL_LOCK_STATUS_CALIBRATING is removed, when dpll is locked with a source signal it shall return DPLL_LOCK_STATUS_LOCKED, if it is capable of holdover with that signal it shall return it's state as: DPLL_LOCK_STATUS_LOCKED_HO_ACQ Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 10 ++++++---- include/uapi/linux/dpll.h | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 76094e1244b8..a0a859c235bf 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -40,12 +40,14 @@ definitions: dpll was not yet locked to any valid source (or is in mode: DPLL_MODE_FREERUN) value: 1 - - - name: calibrating - doc: dpll is trying to lock to a valid signal - name: locked - doc: dpll is locked + doc: | + dpll is locked to a valid signal, but no holdover available + - + name: locked-ho-acq + doc: | + dpll is locked and holdover acquired - name: holdover doc: | diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index cd831a72ea65..cc55d149c143 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -33,8 +33,9 @@ enum dpll_mode { * valid values for DPLL_A_LOCK_STATUS attribute * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid source (or * is in mode: DPLL_MODE_FREERUN) - * @DPLL_LOCK_STATUS_CALIBRATING: dpll is trying to lock to a valid signal - * @DPLL_LOCK_STATUS_LOCKED: dpll is locked + * @DPLL_LOCK_STATUS_LOCKED: dpll is locked to a valid signal, but no holdover + * available + * @DPLL_LOCK_STATUS_LOCKED_HO_ACQ: dpll is locked and holdover acquired * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or * was forced by selecting DPLL_MODE_HOLDOVER mode (latter possible only when * dpll lock-state was already DPLL_LOCK_STATUS_LOCKED, if dpll lock-state @@ -43,8 +44,8 @@ enum dpll_mode { */ enum dpll_lock_status { DPLL_LOCK_STATUS_UNLOCKED = 1, - DPLL_LOCK_STATUS_CALIBRATING, DPLL_LOCK_STATUS_LOCKED, + DPLL_LOCK_STATUS_LOCKED_HO_ACQ, DPLL_LOCK_STATUS_HOLDOVER, __DPLL_LOCK_STATUS_MAX, From 17dcd15a5e1eb748d01dd8f32e1cc98bc197ecea Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 22:55:15 +0200 Subject: [PATCH 47/93] dpll: docs: remove DPLL_LOCK_STATUS_CALIBRATING DPLL_LOCK_STATUS_CALIBRATING is removed, when dpll is locked with a source signal it shall return DPLL_LOCK_STATUS_LOCKED, if it is capable of holdover with that signal it shall return it's state as: DPLL_LOCK_STATUS_LOCKED_HO_ACQ Signed-off-by: Arkadiusz Kubalewski --- Documentation/dpll.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/dpll.rst b/Documentation/dpll.rst index 51e4cbef6ae1..a1cceea7a87d 100644 --- a/Documentation/dpll.rst +++ b/Documentation/dpll.rst @@ -251,10 +251,10 @@ Values for ``DPLL_A_LOCK_STATUS`` attribute: ============================= ====================================== ``LOCK_STATUS_UNLOCKED`` dpll device is in freerun, not locked to any source pin - ``LOCK_STATUS_CALIBRATING`` dpll device calibrates to lock to the - source pin signal ``LOCK_STATUS_LOCKED`` dpll device is locked to the source - pin frequency + but no holodver capability yet acquired + ``LOCK_STATUS_LOCKED_HO_ACQ`` dpll device is locked to the source + pin with holdover capability acquired ``LOCK_STATUS_HOLDOVER`` dpll device lost a lock, using its frequency holdover capabilities From 28f0c7368d453ad1fc50fe69f0b8910ed9774fbf Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 22:55:42 +0200 Subject: [PATCH 48/93] ice: remove DPLL_LOCK_STATUS_CALIBRATING DPLL_LOCK_STATUS_CALIBRATING was removed, return: DPLL_LOCK_STATUS_LOCKED - if dpll was locked DPLL_LOCK_STATUS_LOCKED_HO_ACQ - if dpll was locked and holdover is acquired. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 8aa46763ded1..3420b388e218 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -17,8 +17,8 @@ static const enum dpll_lock_status ice_dpll_status[__DPLL_LOCK_STATUS_MAX] = { [ICE_CGU_STATE_INVALID] = 0, [ICE_CGU_STATE_FREERUN] = DPLL_LOCK_STATUS_UNLOCKED, - [ICE_CGU_STATE_LOCKED] = DPLL_LOCK_STATUS_CALIBRATING, - [ICE_CGU_STATE_LOCKED_HO_ACQ] = DPLL_LOCK_STATUS_LOCKED, + [ICE_CGU_STATE_LOCKED] = DPLL_LOCK_STATUS_LOCKED, + [ICE_CGU_STATE_LOCKED_HO_ACQ] = DPLL_LOCK_STATUS_LOCKED_HO_ACQ, [ICE_CGU_STATE_HOLDOVER] = DPLL_LOCK_STATUS_HOLDOVER, }; From 18611767816e409cb64b73e1e41eee8c47726f0c Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 16 May 2023 23:56:43 +0200 Subject: [PATCH 49/93] ice: propagate and use dpll_priv Propagate and use dpll_priv to obtain pf pointer in corresponding functions. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 68 ++++++++++++----------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 3420b388e218..94119be51691 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -131,6 +131,7 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: pointer to dpll + * @dpll_priv: private data pointer passed on dpll registration * @frequency: frequency to be set * @extack: error reporting * @pin_type: type of pin being configured @@ -143,13 +144,13 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, */ static int ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, + const struct dpll_device *dpll, void *dpll_priv, const u32 frequency, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { + struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; - struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -185,8 +186,8 @@ ice_dpll_source_frequency_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 frequency, struct netlink_ext_ack *extack) { - return ice_dpll_frequency_set(pin, pin_priv, dpll, frequency, extack, - ICE_DPLL_PIN_TYPE_SOURCE); + return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, + extack, ICE_DPLL_PIN_TYPE_SOURCE); } /** @@ -209,8 +210,8 @@ ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 frequency, struct netlink_ext_ack *extack) { - return ice_dpll_frequency_set(pin, pin_priv, dpll, frequency, extack, - ICE_DPLL_PIN_TYPE_OUTPUT); + return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, + extack, ICE_DPLL_PIN_TYPE_OUTPUT); } /** @@ -231,12 +232,12 @@ ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, */ static int ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, u64 *frequency, - struct netlink_ext_ack *extack, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { + struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; - struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -270,8 +271,8 @@ ice_dpll_source_frequency_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 *frequency, struct netlink_ext_ack *extack) { - return ice_dpll_frequency_get(pin, pin_priv, dpll, frequency, extack, - ICE_DPLL_PIN_TYPE_SOURCE); + return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, + extack, ICE_DPLL_PIN_TYPE_SOURCE); } /** @@ -294,8 +295,8 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 *frequency, struct netlink_ext_ack *extack) { - return ice_dpll_frequency_get(pin, pin_priv, dpll, frequency, extack, - ICE_DPLL_PIN_TYPE_OUTPUT); + return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, + extack, ICE_DPLL_PIN_TYPE_OUTPUT); } /** @@ -608,9 +609,10 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, /** * ice_dpll_pin_state_set - set pin's state on dpll - * @dpll: dpll being configured * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration * @state: state of pin to be set * @extack: error reporting * @pin_type: type of a pin @@ -622,14 +624,13 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, * * negative - error */ static int -ice_dpll_pin_state_set(const struct dpll_device *dpll, - const struct dpll_pin *pin, void *pin_priv, - bool enable, - struct netlink_ext_ack *extack, +ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + bool enable, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { + struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; - struct ice_pf *pf = p->pf; int ret = -EINVAL; if (!pf) @@ -676,8 +677,8 @@ static int ice_dpll_output_state_set(const struct dpll_pin *pin, { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; - return ice_dpll_pin_state_set(dpll, pin, pin_priv, enable, extack, - ICE_DPLL_PIN_TYPE_OUTPUT); + return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, + extack, ICE_DPLL_PIN_TYPE_OUTPUT); } /** @@ -704,15 +705,16 @@ static int ice_dpll_source_state_set(const struct dpll_pin *pin, { bool enable = state == DPLL_PIN_STATE_SELECTABLE ? true : false; - return ice_dpll_pin_state_set(dpll, pin, pin_priv, enable, extack, - ICE_DPLL_PIN_TYPE_SOURCE); + return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, + extack, ICE_DPLL_PIN_TYPE_SOURCE); } /** * ice_dpll_pin_state_get - set pin's state on dpll - * @dpll: registered dpll pointer * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration + * @dpll: registered dpll pointer + * @dpll_priv: private data pointer passed on dpll registration * @state: on success holds state of the pin * @extack: error reporting * @pin_type: type of questioned pin @@ -724,14 +726,14 @@ static int ice_dpll_source_state_set(const struct dpll_pin *pin, * * negative - failed to get state */ static int -ice_dpll_pin_state_get(const struct dpll_device *dpll, - const struct dpll_pin *pin, void *pin_priv, +ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, enum dpll_pin_state *state, struct netlink_ext_ack *extack, const enum ice_dpll_pin_type pin_type) { + struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; - struct ice_pf *pf = p->pf; struct ice_dpll *d; int ret = -EINVAL; @@ -783,8 +785,8 @@ static int ice_dpll_output_state_get(const struct dpll_pin *pin, enum dpll_pin_state *state, struct netlink_ext_ack *extack) { - return ice_dpll_pin_state_get(dpll, pin, pin_priv, state, extack, - ICE_DPLL_PIN_TYPE_OUTPUT); + return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, + extack, ICE_DPLL_PIN_TYPE_OUTPUT); } /** @@ -809,8 +811,8 @@ static int ice_dpll_source_state_get(const struct dpll_pin *pin, enum dpll_pin_state *state, struct netlink_ext_ack *extack) { - return ice_dpll_pin_state_get(dpll, pin, pin_priv, state, extack, - ICE_DPLL_PIN_TYPE_SOURCE); + return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, + extack, ICE_DPLL_PIN_TYPE_SOURCE); } /** @@ -835,7 +837,7 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, { struct ice_dpll_pin *p = pin_priv; struct ice_dpll *d = dpll_priv; - struct ice_pf *pf = p->pf; + struct ice_pf *pf = d->pf; int ret = -EINVAL; if (!pf) @@ -874,7 +876,7 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, { struct ice_dpll_pin *p = pin_priv; struct ice_dpll *d = dpll_priv; - struct ice_pf *pf = p->pf; + struct ice_pf *pf = d->pf; int ret = -EINVAL; if (!pf) From b6d0c19f4e34bf5527b37e8902a50afe5d94cb8b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 17 May 2023 00:14:35 +0200 Subject: [PATCH 50/93] ice: remove null check for pf pointer Pointer is given back from dpll subsystem, it cannot null unless dpll subsystem is broken. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 30 ----------------------- 1 file changed, 30 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 94119be51691..a9b1202f77a0 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -153,8 +153,6 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, struct ice_dpll_pin *p = pin_priv; int ret = -EINVAL; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -240,8 +238,6 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, struct ice_dpll_pin *p = pin_priv; int ret = -EINVAL; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -538,8 +534,6 @@ static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, struct ice_pf *pf = d->pf; int ret = -EINVAL; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -568,11 +562,6 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *priv, enum dpll_mode *mode, struct netlink_ext_ack *extack) { - struct ice_dpll *d = priv; - struct ice_pf *pf = d->pf; - - if (!pf) - return -EINVAL; *mode = DPLL_MODE_AUTOMATIC; return 0; @@ -596,11 +585,6 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, const enum dpll_mode mode, struct netlink_ext_ack *extack) { - struct ice_dpll *d = priv; - struct ice_pf *pf = d->pf; - - if (!pf) - return false; if (mode == DPLL_MODE_AUTOMATIC) return true; @@ -633,8 +617,6 @@ ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, struct ice_dpll_pin *p = pin_priv; int ret = -EINVAL; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -737,8 +719,6 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, struct ice_dpll *d; int ret = -EINVAL; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -840,9 +820,6 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, struct ice_pf *pf = d->pf; int ret = -EINVAL; - if (!pf) - return ret; - ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -879,9 +856,6 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, struct ice_pf *pf = d->pf; int ret = -EINVAL; - if (!pf) - return ret; - if (prio > ICE_DPLL_PRIO_MAX) { NL_SET_ERR_MSG_FMT(extack, "prio out of supported range 0-%d", ICE_DPLL_PRIO_MAX); @@ -981,8 +955,6 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, int ret = -EINVAL; u32 hw_idx; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; @@ -1032,8 +1004,6 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, int ret = -EFAULT; u32 hw_idx; - if (!pf) - return ret; ret = ice_dpll_cb_lock(pf); if (ret) return ret; From a3f389340f32230959f099b60b8ff812866c8bd5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 17 May 2023 00:46:53 +0200 Subject: [PATCH 51/93] dpll: spec: fix notification definition Define notifications as commands as expected by yaml spec. Add separated notification for pin events. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 49 ++++++++++++++++----------- include/uapi/linux/dpll.h | 19 ++++------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index a0a859c235bf..6cd7a3c85b51 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -168,24 +168,6 @@ definitions: name: priority-can-change - name: state-can-change - - - type: enum - name: event - doc: events of dpll generic netlink family - entries: - - - name: device-create - doc: dpll device created - value: 1 - - - name: device-delete - doc: dpll device deleted - - - name: device-change - doc: | - attribute of dpll device or pin changed, reason is to be found with - an attribute type (DPLL_A_*) received with the event - attribute-sets: - @@ -375,7 +357,21 @@ operations: - bus-name - dev-name - mode - + - + name: device-create-ntf + doc: Notification about device appearing + notify: device-get + mcgrp: monitor + - + name: device-delete-ntf + doc: Notification about device disappearing + notify: device-get + mcgrp: monitor + - + name: device-change-ntf + doc: Notification about device configuration being changed + notify: device-get + mcgrp: monitor - name: pin-get doc: | @@ -437,6 +433,21 @@ operations: - pin-prio - pin-state - pin-parent-idx + - + name: pin-create-ntf + doc: Notification about pin appearing + notify: pin-get + mcgrp: monitor + - + name: pin-delete-ntf + doc: Notification about pin disappearing + notify: pin-get + mcgrp: monitor + - + name: pin-change-ntf + doc: Notification about pin configuration being changed + notify: pin-get + mcgrp: monitor mcast-groups: list: diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index cc55d149c143..511b213b30c7 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -133,19 +133,6 @@ enum dpll_pin_caps { DPLL_PIN_CAPS_STATE_CAN_CHANGE = 4, }; -/** - * enum dpll_event - events of dpll generic netlink family - * @DPLL_EVENT_DEVICE_CREATE: dpll device created - * @DPLL_EVENT_DEVICE_DELETE: dpll device deleted - * @DPLL_EVENT_DEVICE_CHANGE: attribute of dpll device or pin changed, reason - * is to be found with an attribute type (DPLL_A_*) received with the event - */ -enum dpll_event { - DPLL_EVENT_DEVICE_CREATE = 1, - DPLL_EVENT_DEVICE_DELETE, - DPLL_EVENT_DEVICE_CHANGE, -}; - enum dplla { DPLL_A_ID = 1, DPLL_A_DEV_NAME, @@ -179,8 +166,14 @@ enum dplla { enum { DPLL_CMD_DEVICE_GET = 1, DPLL_CMD_DEVICE_SET, + DPLL_CMD_DEVICE_CREATE_NTF, + DPLL_CMD_DEVICE_DELETE_NTF, + DPLL_CMD_DEVICE_CHANGE_NTF, DPLL_CMD_PIN_GET, DPLL_CMD_PIN_SET, + DPLL_CMD_PIN_CREATE_NTF, + DPLL_CMD_PIN_DELETE_NTF, + DPLL_CMD_PIN_CHANGE_NTF, __DPLL_CMD_MAX, DPLL_CMD_MAX = (__DPLL_CMD_MAX - 1) From 64a71d339aad9fa640213f6f9097e5bc8aaacc2e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 17 May 2023 00:49:07 +0200 Subject: [PATCH 52/93] dpll: core: fix notification definition Align with new notification names. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 453fc07622b1..e1e515518382 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -885,7 +885,7 @@ dpll_event_device_change(struct sk_buff *msg, struct dpll_device *dpll, } static int -dpll_send_event_create(enum dpll_event event, struct dpll_device *dpll) +dpll_send_event_create(enum dplla event, struct dpll_device *dpll) { struct sk_buff *msg; int ret = -EMSGSIZE; @@ -928,7 +928,7 @@ dpll_send_event_change(struct dpll_device *dpll, struct dpll_pin *pin, return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, - DPLL_EVENT_DEVICE_CHANGE); + DPLL_CMD_DEVICE_CHANGE_NTF); if (!hdr) goto out_free_msg; @@ -950,12 +950,12 @@ dpll_send_event_change(struct dpll_device *dpll, struct dpll_pin *pin, int dpll_notify_device_create(struct dpll_device *dpll) { - return dpll_send_event_create(DPLL_EVENT_DEVICE_CREATE, dpll); + return dpll_send_event_create(DPLL_CMD_DEVICE_CREATE_NTF, dpll); } int dpll_notify_device_delete(struct dpll_device *dpll) { - return dpll_send_event_create(DPLL_EVENT_DEVICE_DELETE, dpll); + return dpll_send_event_create(DPLL_CMD_DEVICE_DELETE_NTF, dpll); } int dpll_device_notify(struct dpll_device *dpll, enum dplla attr) From 950e24fdc5c71f832aef5e7f32a2902d83117161 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 18 May 2023 11:47:13 +0200 Subject: [PATCH 53/93] dpll: fix notification scheme Use separated notifications for dpll pins and devices. Format the messages as corresponding get netlink commands. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 12 ++- drivers/dpll/dpll_netlink.c | 169 +++++++++++++----------------------- drivers/dpll/dpll_netlink.h | 30 +++++-- include/linux/dpll.h | 22 +++-- 4 files changed, 105 insertions(+), 128 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index c325dd401166..265d621d5b26 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -484,7 +484,7 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); mutex_unlock(&dpll_xa_lock); - dpll_notify_device_create(dpll); + dpll_device_create_ntf(dpll); return 0; } @@ -506,7 +506,7 @@ void dpll_device_unregister(struct dpll_device *dpll, mutex_lock(&dpll_xa_lock); ASSERT_DPLL_REGISTERED(dpll); - + dpll_device_delete_ntf(dpll); reg = dpll_device_registration_find(dpll, ops, priv); if (WARN_ON(!reg)) { mutex_unlock(&dpll_xa_lock); @@ -521,7 +521,6 @@ void dpll_device_unregister(struct dpll_device *dpll, } xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); mutex_unlock(&dpll_xa_lock); - dpll_notify_device_delete(dpll); } EXPORT_SYMBOL_GPL(dpll_device_unregister); @@ -673,7 +672,7 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, if (ret) goto ref_pin_del; else - dpll_pin_notify(dpll, pin, DPLL_A_PIN_IDX); + dpll_pin_create_ntf(pin); return ret; @@ -783,7 +782,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, stop = i; goto dpll_unregister; } - dpll_pin_parent_notify(ref->dpll, pin, parent, DPLL_A_PIN_IDX); + dpll_pin_create_ntf(pin); } return ret; @@ -819,12 +818,11 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, unsigned long i; mutex_lock(&dpll_xa_lock); + dpll_pin_delete_ntf(pin); dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); refcount_dec(&pin->refcount); xa_for_each(&pin->dpll_refs, i, ref) { __dpll_pin_unregister(ref->dpll, pin, ops, priv); - dpll_pin_parent_notify(ref->dpll, pin, parent, - DPLL_A_PIN_IDX); } mutex_unlock(&dpll_xa_lock); } diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index e1e515518382..5a6dc45a0997 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -12,6 +12,8 @@ #include "dpll_nl.h" #include +static int __dpll_pin_change_ntf(struct dpll_pin *pin); + struct dpll_dump_ctx { unsigned long idx; }; @@ -399,7 +401,7 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, dpll, dpll_priv(dpll), freq, extack); if (ret) return -EFAULT; - dpll_pin_notify(dpll, pin, DPLL_A_PIN_FREQUENCY); + __dpll_pin_change_ntf(pin); } return 0; @@ -432,8 +434,7 @@ dpll_pin_on_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, dpll_pin_on_dpll_priv(dpll, parent_ref->pin), state, extack)) return -EFAULT; - dpll_pin_parent_notify(dpll, pin_ref->pin, parent_ref->pin, - DPLL_A_PIN_STATE); + __dpll_pin_change_ntf(pin_ref->pin); return 0; } @@ -457,7 +458,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, if (ops->state_on_dpll_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, dpll_priv(dpll), state, extack)) return -EINVAL; - dpll_pin_notify(dpll, pin, DPLL_A_PIN_STATE); + __dpll_pin_change_ntf(pin); return 0; } @@ -481,7 +482,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, if (ops->prio_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll, dpll_priv(dpll), prio, extack)) return -EINVAL; - dpll_pin_notify(dpll, pin, DPLL_A_PIN_PRIO); + __dpll_pin_change_ntf(pin); return 0; } @@ -505,7 +506,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct nlattr *a, dpll, dpll_priv(dpll), direction, extack)) return -EFAULT; - dpll_pin_notify(dpll, pin, DPLL_A_PIN_DIRECTION); + __dpll_pin_change_ntf(pin); } return 0; @@ -813,93 +814,22 @@ int dpll_pin_post_dumpit(struct netlink_callback *cb) } static int -dpll_event_device_change(struct sk_buff *msg, struct dpll_device *dpll, - struct dpll_pin *pin, struct dpll_pin *parent, - enum dplla attr) -{ - int ret = dpll_msg_add_dev_handle(msg, dpll); - struct dpll_pin_ref *ref = NULL; - enum dpll_pin_state state; - - if (ret) - return ret; - if (pin && nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) - return -EMSGSIZE; - - switch (attr) { - case DPLL_A_MODE: - ret = dpll_msg_add_mode(msg, dpll, NULL); - break; - case DPLL_A_LOCK_STATUS: - ret = dpll_msg_add_lock_status(msg, dpll, NULL); - break; - case DPLL_A_TEMP: - ret = dpll_msg_add_temp(msg, dpll, NULL); - break; - case DPLL_A_PIN_FREQUENCY: - ref = xa_load(&pin->dpll_refs, dpll->device_idx); - if (!ref) - return -EFAULT; - ret = dpll_msg_add_pin_freq(msg, pin, ref, NULL, false); - break; - case DPLL_A_PIN_PRIO: - ref = xa_load(&pin->dpll_refs, dpll->device_idx); - if (!ref) - return -EFAULT; - ret = dpll_msg_add_pin_prio(msg, pin, ref, NULL); - break; - case DPLL_A_PIN_STATE: - if (parent) { - void *parent_priv = dpll_pin_on_dpll_priv(dpll, parent); - void *priv = dpll_pin_on_pin_priv(parent, pin); - const struct dpll_pin_ops *ops; - - ref = xa_load(&pin->parent_refs, parent->pin_idx); - if (!ref) - return -EFAULT; - ops = dpll_pin_ops(ref); - if (!ops->state_on_pin_get) - return -EOPNOTSUPP; - ret = ops->state_on_pin_get(pin, priv, parent, - parent_priv, &state, NULL); - if (ret) - return ret; - if (nla_put_u32(msg, DPLL_A_PIN_PARENT_IDX, - parent->pin_idx)) - return -EMSGSIZE; - } else { - ref = xa_load(&pin->dpll_refs, dpll->device_idx); - if (!ref) - return -EFAULT; - ret = dpll_msg_add_pin_on_dpll_state(msg, pin, ref, - NULL); - if (ret) - return ret; - } - break; - default: - break; - } - - return ret; -} - -static int -dpll_send_event_create(enum dplla event, struct dpll_device *dpll) +dpll_device_event_send(enum dplla event, struct dpll_device *dpll) { struct sk_buff *msg; int ret = -EMSGSIZE; void *hdr; + if (!xa_get_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED)) + return -ENODEV; + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); if (!hdr) goto out_free_msg; - - ret = dpll_msg_add_dev_handle(msg, dpll); + ret = dpll_device_get_one(dpll, msg, NULL); if (ret) goto out_cancel_msg; genlmsg_end(msg, hdr); @@ -915,24 +845,51 @@ dpll_send_event_create(enum dplla event, struct dpll_device *dpll) return ret; } +int dpll_device_create_ntf(struct dpll_device *dpll) +{ + return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll); +} + +int dpll_device_delete_ntf(struct dpll_device *dpll) +{ + return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); +} + +int dpll_device_change_ntf(struct dpll_device *dpll) +{ + int ret = -EINVAL; + + if (WARN_ON(!dpll)) + return ret; + + mutex_lock(&dpll_xa_lock); + ret = dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); + mutex_unlock(&dpll_xa_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_device_change_ntf); + static int -dpll_send_event_change(struct dpll_device *dpll, struct dpll_pin *pin, - struct dpll_pin *parent, enum dplla attr) +dpll_pin_event_send(enum dplla event, struct dpll_pin *pin) { + struct dpll_pin *pin_verify; struct sk_buff *msg; int ret = -EMSGSIZE; void *hdr; + pin_verify = xa_load(&dpll_pin_xa, pin->id); + if (pin != pin_verify) + return -ENODEV; + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) return -ENOMEM; - hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, - DPLL_CMD_DEVICE_CHANGE_NTF); + hdr = genlmsg_put(msg, 0, 0, &dpll_nl_family, 0, event); if (!hdr) goto out_free_msg; - - ret = dpll_event_device_change(msg, dpll, pin, parent, attr); + ret = __dpll_cmd_pin_dump_one(msg, pin, NULL); if (ret) goto out_cancel_msg; genlmsg_end(msg, hdr); @@ -948,37 +905,35 @@ dpll_send_event_change(struct dpll_device *dpll, struct dpll_pin *pin, return ret; } -int dpll_notify_device_create(struct dpll_device *dpll) +int dpll_pin_create_ntf(struct dpll_pin *pin) { - return dpll_send_event_create(DPLL_CMD_DEVICE_CREATE_NTF, dpll); + return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin); } -int dpll_notify_device_delete(struct dpll_device *dpll) +int dpll_pin_delete_ntf(struct dpll_pin *pin) { - return dpll_send_event_create(DPLL_CMD_DEVICE_DELETE_NTF, dpll); + return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); } -int dpll_device_notify(struct dpll_device *dpll, enum dplla attr) +static int __dpll_pin_change_ntf(struct dpll_pin *pin) { - if (WARN_ON(!dpll)) - return -EINVAL; - - return dpll_send_event_change(dpll, NULL, NULL, attr); + return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); } -EXPORT_SYMBOL_GPL(dpll_device_notify); -int dpll_pin_notify(struct dpll_device *dpll, struct dpll_pin *pin, - enum dplla attr) +int dpll_pin_change_ntf(struct dpll_pin *pin) { - return dpll_send_event_change(dpll, pin, NULL, attr); -} -EXPORT_SYMBOL_GPL(dpll_pin_notify); + int ret = -EINVAL; -int dpll_pin_parent_notify(struct dpll_device *dpll, struct dpll_pin *pin, - struct dpll_pin *parent, enum dplla attr) -{ - return dpll_send_event_change(dpll, pin, parent, attr); + if (WARN_ON(!pin)) + return ret; + + mutex_lock(&dpll_xa_lock); + ret = __dpll_pin_change_ntf(pin); + mutex_unlock(&dpll_xa_lock); + + return ret; } +EXPORT_SYMBOL_GPL(dpll_pin_change_ntf); int __init dpll_netlink_init(void) { diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h index 952e0335595e..3227f4707900 100644 --- a/drivers/dpll/dpll_netlink.h +++ b/drivers/dpll/dpll_netlink.h @@ -4,24 +4,40 @@ */ /** - * dpll_notify_device_create - notify that the device has been created + * dpll_device_create_ntf - notify that the device has been created * @dpll: registered dpll pointer * + * Context: caller shall hold dpll_xa_lock. * Return: 0 if succeeds, error code otherwise. */ -int dpll_notify_device_create(struct dpll_device *dpll); - +int dpll_device_create_ntf(struct dpll_device *dpll); /** - * dpll_notify_device_delete - notify that the device has been deleted + * dpll_device_delete_ntf - notify that the device has been deleted * @dpll: registered dpll pointer * + * Context: caller shall hold dpll_xa_lock. + * Return: 0 if succeeds, error code otherwise. + */ +int dpll_device_delete_ntf(struct dpll_device *dpll); + +/** + * dpll_pin_delete_ntf - notify that the pin has been deleted + * @pin: registered pin pointer + * + * Context: caller shall hold dpll_xa_lock. * Return: 0 if succeeds, error code otherwise. */ -int dpll_notify_device_delete(struct dpll_device *dpll); +int dpll_pin_create_ntf(struct dpll_pin *pin); -int dpll_pin_parent_notify(struct dpll_device *dpll, struct dpll_pin *pin, - struct dpll_pin *parent, enum dplla attr); +/** + * dpll_pin_delete_ntf - notify that the pin has been deleted + * @pin: registered pin pointer + * + * Context: caller shall hold dpll_xa_lock. + * Return: 0 if succeeds, error code otherwise. + */ +int dpll_pin_delete_ntf(struct dpll_pin *pin); int __init dpll_netlink_init(void); void dpll_netlink_finish(void); diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 93b59b13ac9d..21b448b5883f 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -276,21 +276,29 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv); /** - * dpll_device_notify - notify on dpll device change + * dpll_device_change_ntf - notify on dpll device change * @dpll: dpll device pointer - * @attr: changed attribute * * Broadcast event to the netlink multicast registered listeners. * + * Context: Takes and releases a dpll_xa_lock. * Return: * * 0 - success * * negative - error */ -int dpll_device_notify(struct dpll_device *dpll, enum dplla attr); - -int dpll_pin_notify(struct dpll_device *dpll, struct dpll_pin *pin, - enum dplla attr); - +int dpll_device_change_ntf(struct dpll_device *dpll); +/** + * dpll_device_change_ntf - notify on dpll device change + * @dpll: dpll device pointer + * + * Broadcast event to the netlink multicast registered listeners. + * + * Context: Takes and releases a dpll_xa_lock. + * Return: + * * 0 - success + * * negative - error + */ +int dpll_pin_change_ntf(struct dpll_pin *pin); #endif From a93cc8e739e835c8d4bda85f0e7b6d5bb87561cd Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 18 May 2023 11:49:21 +0200 Subject: [PATCH 54/93] ice: fix notification scheme Align with fixed notification scheme in dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index a9b1202f77a0..d3fbe04726a4 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1344,16 +1344,14 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) { if (d->prev_dpll_state != d->dpll_state) { d->prev_dpll_state = d->dpll_state; - dpll_device_notify(d->dpll, DPLL_A_LOCK_STATUS); + dpll_device_change_ntf(d->dpll); } if (d->prev_source != d->active_source) { if (d->prev_source) - dpll_pin_notify(d->dpll, d->prev_source, - DPLL_A_PIN_STATE); + dpll_pin_change_ntf(d->prev_source); d->prev_source = d->active_source; if (d->active_source) - dpll_pin_notify(d->dpll, d->active_source, - DPLL_A_PIN_STATE); + dpll_pin_change_ntf(d->active_source); } } From bfc80f794a3de13eaeec111e664ec490afd45b44 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 18 May 2023 11:50:28 +0200 Subject: [PATCH 55/93] mlx5: fix notification scheme Align with fixed notification scheme in dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/mellanox/mlx5/core/dpll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 1469ddbafec7..16ba26f43cfc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -235,9 +235,9 @@ static void mlx5_dpll_periodic_work(struct work_struct *work) goto invalid_out; if (mdpll->last.lock_status != lock_status) - dpll_device_notify(mdpll->dpll, DPLL_A_LOCK_STATUS); + dpll_device_change_ntf(mdpll->dpll); if (mdpll->last.pin_state != pin_state) - dpll_pin_notify(mdpll->dpll, mdpll->dpll_pin, DPLL_A_PIN_STATE); + dpll_pin_change_ntf(mdpll->dpll_pin); invalid_out: mdpll->last.lock_status = lock_status; From 8c42841ca7344cbffd342a34c96f2effd52072c7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 17 May 2023 23:26:36 +0200 Subject: [PATCH 56/93] ice: expose pf related pin to corresponding netdevice Register a recoered clock pin of a pf in its netdevice struct. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index d3fbe04726a4..236a12b488fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1084,6 +1084,7 @@ static void ice_dpll_release_rclk_pin(struct ice_pf *pf) { struct ice_dpll_pin *rclk = &pf->dplls.rclk; + struct ice_vsi *vsi = ice_get_main_vsi(pf); struct dpll_pin *parent; int i; @@ -1094,6 +1095,9 @@ ice_dpll_release_rclk_pin(struct ice_pf *pf) dpll_pin_on_pin_unregister(parent, rclk->pin, &ice_dpll_rclk_ops, rclk); } + if (WARN_ON_ONCE(!vsi || !vsi->netdev)) + return; + netdev_dpll_pin_clear(vsi->netdev); dpll_pin_put(rclk->pin); rclk->pin = NULL; } @@ -1202,11 +1206,16 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) for (i = 0; i < pf->dplls.rclk.num_parents; i++) { struct dpll_pin *parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; + struct ice_vsi *vsi = ice_get_main_vsi(pf); ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, ops, &pf->dplls.rclk, dev); if (ret) return ret; + + if (!vsi || !vsi->netdev) + return -EINVAL; + netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin); } return 0; From 9f5c7ac939ba122626e5b5a29411100f217e588e Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 18 May 2023 00:02:02 +0200 Subject: [PATCH 57/93] dpll: docs: add grepability Use full names of commands, attributes and values of dpll subsystem in the documentation. Signed-off-by: Arkadiusz Kubalewski --- Documentation/dpll.rst | 280 ++++++++++++++++++++--------------------- 1 file changed, 137 insertions(+), 143 deletions(-) diff --git a/Documentation/dpll.rst b/Documentation/dpll.rst index a1cceea7a87d..6ce07ccc3f1d 100644 --- a/Documentation/dpll.rst +++ b/Documentation/dpll.rst @@ -75,9 +75,10 @@ Shared pins A single pin object can be registered to multiple dpll devices. Then there are two groups of configuration knobs: 1) Set on a pin - the configuration affects all dpll devices pin is - registered to. (i.e. ``PIN_FREQUENCY``, ``PIN_DIRECTION``), + registered to. (i.e. ``DPLL_A_PIN_FREQUENCY``, + ``DPLL_A_PIN_DIRECTION``), 2) Set on a pin-dpll tuple - the configuration affects only selected - dpll device. (i.e. PIN_PRIO, PIN_STATE). + dpll device. (i.e. ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``). MUX-type pins @@ -150,172 +151,166 @@ All constants identifying command types use ``DPLL_CMD_`` prefix and suffix according to command purpose. All attributes use ``DPLL_A_`` prefix and suffix according to attribute purpose: - ============================ ======================================= - ``DEVICE_GET`` command to get device info or dump list - of available devices - ``ID`` attr internal dpll device ID - ``DEV_NAME`` attr dpll device name - ``BUS_NAME`` attr dpll device bus name - ``MODE`` attr selection mode - ``MODE_SUPPORTED`` attr available selection modes - ``LOCK_STATUS`` attr internal frequency-lock status - ``TEMP`` attr device temperature information - ``CLOCK_ID`` attr Unique Clock Identifier (EUI-64), - as defined by the IEEE 1588 standard - ``TYPE`` attr type or purpose of dpll device - ``DEVICE_SET`` command to set dpll device configuration - ``ID`` attr internal dpll device index - ``NAME`` attr dpll device name (not required if - dpll device index was provided) - ``MODE`` attr selection mode to configure - ``PIN_GET`` command to get pin info or dump list of - available pins - ``DEVICE`` nest attr for each dpll device pin is - connected with - ``ID`` attr internal dpll device ID - ``DEV_NAME`` attr dpll device name - ``BUS_NAME`` attr dpll device bus name - ``PIN_PRIO`` attr priority of pin on the dpll device - ``PIN_STATE`` attr state of pin on the dpll device - ``PIN_IDX`` attr index of a pin on the dpll device - ``PIN_DESCRIPTION`` attr description provided by driver - ``PIN_TYPE`` attr type of a pin - ``PIN_DIRECTION`` attr direction of a pin - ``PIN_FREQUENCY`` attr current frequency of a pin - ``PIN_FREQUENCY_SUPPORTED`` attr provides supported frequencies - ``PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency in case - pin/dpll supports any frequency - ``PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency in case - pin/dpll supports any frequency - ``PIN_PARENT`` nest attr for each MUX-type parent, that - pin is connected with - ``PIN_PARENT_IDX`` attr index of a parent pin on the dpll - device - ``PIN_STATE`` attr state of a pin on parent pin - ``PIN_RCLK_DEVICE`` attr name of a device, where pin - recovers clock signal from - ``PIN_DPLL_CAPS`` attr bitmask of pin-dpll capabilities - - ``PIN_SET`` command to set pins configuration - ``ID`` attr internal dpll device index - ``BUS_NAME`` attr dpll device name (not required if - dpll device ID was provided) - ``DEV_NAME`` attr dpll device name (not required if - dpll device ID was provided) - ``PIN_IDX`` attr index of a pin on the dpll device - ``PIN_DIRECTION`` attr direction to be set - ``PIN_FREQUENCY`` attr frequency to be set - ``PIN_PRIO`` attr pin priority to be set - ``PIN_STATE`` attr pin state to be set - ``PIN_PARENT_IDX`` attr if provided state is to be set with - parent pin instead of with dpll device + ==================================== ======================================= + ``DPLL_CMD_DEVICE_GET`` command to get device info or dump list + of available devices + ``DPLL_A_ID`` attr internal dpll device ID + ``DPLL_A_DEV_NAME`` attr dpll device name + ``DPLL_A_BUS_NAME`` attr dpll device bus name + ``DPLL_A_MODE`` attr selection mode + ``DPLL_A_MODE_SUPPORTED`` attr available selection modes + ``DPLL_A_LOCK_STATUS`` attr internal frequency-lock status + ``DPLL_A_TEMP`` attr device temperature information + ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier (EUI-64), + as defined by the IEEE 1588 standard + ``DPLL_A_TYPE`` attr type or purpose of dpll device + ``DPLL_CMD_DEVICE_SET`` command to set dpll device configuration + ``DPLL_A_ID`` attr internal dpll device index + ``DPLL_A_NAME`` attr dpll device name (not required if + dpll device index was provided) + ``DPLL_A_MODE`` attr selection mode to configure + ``DPLL_CMD_PIN_GET`` command to get pin info or dump list of + available pins + ``DPLL_A_DEVICE`` nest attr for each dpll device pin is + connected with + ``DPLL_A_ID`` attr internal dpll device ID + ``DPLL_A_DEV_NAME`` attr dpll device name + ``DPLL_A_BUS_NAME`` attr dpll device bus name + ``DPLL_A_PIN_PRIO`` attr priority of pin on the dpll device + ``DPLL_A_PIN_STATE`` attr state of pin on the dpll device + ``DPLL_A_PIN_IDX`` attr index of a pin on the dpll device + ``DPLL_A_PIN_DESCRIPTION`` attr description provided by driver + ``DPLL_A_PIN_TYPE`` attr type of a pin + ``DPLL_A_PIN_DIRECTION`` attr direction of a pin + ``DPLL_A_PIN_FREQUENCY`` attr current frequency of a pin + ``DPLL_A_PIN_FREQUENCY_SUPPORTED`` attr provides supported frequencies + ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency in case + pin/dpll supports any frequency + ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency in case + pin/dpll supports any frequency + ``DPLL_A_PIN_PARENT`` nest attr for each MUX-type parent, that + pin is connected with + ``DPLL_A_PIN_PARENT_IDX`` attr index of a parent pin on the dpll + device + ``DPLL_A_PIN_STATE`` attr state of a pin on parent pin + ``DPLL_A_PIN_RCLK_DEVICE`` attr name of a device, where pin + recovers clock signal from + ``DPLL_A_PIN_DPLL_CAPS`` attr bitmask of pin-dpll capabilities + + ``DPLL_CMD_PIN_SET`` command to set pins configuration + ``DPLL_A_ID`` attr internal dpll device index + ``DPLL_A_BUS_NAME`` attr dpll device name (not required if + dpll device ID was provided) + ``DPLL_A_DEV_NAME`` attr dpll device name (not required if + dpll device ID was provided) + ``DPLL_A_PIN_IDX`` attr index of a pin on the dpll device + ``DPLL_A_PIN_DIRECTION`` attr direction to be set + ``DPLL_A_PIN_FREQUENCY`` attr frequency to be set + ``DPLL_A_PIN_PRIO`` attr pin priority to be set + ``DPLL_A_PIN_STATE`` attr pin state to be set + ``DPLL_A_PIN_PARENT_IDX`` attr if provided state is to be set with + parent pin instead of with dpll device Netlink dump requests ===================== -The ``DEVICE_GET`` and ``PIN_GET`` commands are capable of dump type -netlink requests, in which case the response is in the same format as -for their ``do`` request. +The ``DPLL_CMD_DEVICE_GET`` and ``DPLL_CMD_PIN_GET`` commands are +capable of dump type netlink requests, in which case the response is in +the same format as for their ``do`` request. SET commands format =================== -``DEVICE_SET`` - to target a dpll device, the user provides either a -``ID`` or both ``BUS_NAME`` and ``DEV_NAME``, as well as parameter being -configured (``DPLL_A_MODE``). - -``PIN_SET`` - to target a pin user has to provide a ``PIN_IDX``, but -pin does not exist on its own, thus a dpll device must be also targeted -with either a ``ID`` or both ``BUS_NAME`` and ``DEV_NAME`` to which -pin being configured was registered with. Also configured pin parameters -must be added. -If ``PIN_DIRECTION`` or ``PIN_FREQUENCY`` are configured, this affects -all the dpll device they are connected. -If ``PIN_PRIO`` or ``PIN_STATE`` are configured, this affects only +``DPLL_CMD_DEVICE_SET`` - to target a dpll device, the user provides either a +``DPLL_A_ID`` or both ``DPLL_A_BUS_NAME`` and ``DPLL_A_DEV_NAME``, as well as +parameter being configured (``DPLL_A_MODE``). + +``DPLL_CMD_PIN_SET`` - to target a pin user has to provide a ``DPLL_A_PIN_IDX``, +but pin does not exist on its own, thus a dpll device must be also targeted +with either a ``DPLL_A_ID`` or both ``DPLL_A_BUS_NAME`` and ``DPLL_A_DEV_NAME`` +to which pin being configured was registered with. Also configured pin +parameters must be added. +If ``DPLL_A_PIN_DIRECTION`` or ``DPLL_A_PIN_FREQUENCY`` are configured, this +affects all the dpll device they are connected. +If ``DPLL_A_PIN_PRIO`` or ``DPLL_A_PIN_STATE`` are configured, this affects only the dpll device being targeted. -If valid ``PIN_PARENT_IDX`` is provided, the set command shall affect +If valid ``DPLL_A_PIN_PARENT_IDX`` is provided, the set command shall affect the configuration between a pin and it's parent, which is a -``PIN_STATE``. +``DPLL_A_PIN_STATE``. In general it is possible to configure multiple parameters at once. Device level configuration pre-defined enums ================================================= -For all below enum names used for configuration of dpll device use -the ``DPLL_`` prefix. - Values for ``DPLL_A_LOCK_STATUS`` attribute: - ============================= ====================================== - ``LOCK_STATUS_UNLOCKED`` dpll device is in freerun, not locked - to any source pin - ``LOCK_STATUS_LOCKED`` dpll device is locked to the source - but no holodver capability yet acquired - ``LOCK_STATUS_LOCKED_HO_ACQ`` dpll device is locked to the source - pin with holdover capability acquired - ``LOCK_STATUS_HOLDOVER`` dpll device lost a lock, using its - frequency holdover capabilities + ================================== ====================================== + ``DPLL_LOCK_STATUS_UNLOCKED`` dpll device is in freerun, not locked + to any source pin + ``DPLL_LOCK_STATUS_LOCKED`` dpll device is locked to the source + but no holodver capability yet acquired + ``DPLL_LOCK_STATUS_LOCKED_HO_ACQ`` dpll device is locked to the source + pin with holdover capability acquired + ``DPLL_LOCK_STATUS_HOLDOVER`` dpll device lost a lock, using its + frequency holdover capabilities Values for ``DPLL_A_MODE`` attribute: - =================== ================================================ - ``MODE_MANUAL`` source pin is manually selected by setting pin - state to ``DPLL_PIN_STATE_CONNECTED`` on a dpll - ``MODE_AUTOMATIC`` source pin is auto selected according to - configured pin priorities and source signal - validity - ``MODE_HOLDOVER`` force holdover mode of dpll - ``MODE_FREERUN`` dpll device is driven by supplied system clock - without holdover capabilities + ======================= ================================================ + ``DPLL_MODE_MANUAL`` source pin is manually selected by setting pin + state to ``DPLL_PIN_STATE_CONNECTED`` on a dpll + ``DPLL_MODE_AUTOMATIC`` source pin is auto selected according to + configured pin priorities and source signal + validity + ``DPLL_MODE_HOLDOVER`` force holdover mode of dpll + ``DPLL_MODE_FREERUN`` dpll device is driven by supplied system clock + without holdover capabilities Values for ``DPLL_A_TYPE`` attribute: - ============= =================================================== - ``TYPE_PPS`` dpll device used to provide pulse-per-second output - ``TYPE_EEC`` dpll device used to drive ethernet equipment clock + ================= =================================================== + ``DPLL_TYPE_PPS`` dpll device used to provide pulse-per-second output + ``DPLL_TYPE_EEC`` dpll device used to drive ethernet equipment clock Pin level configuration pre-defined enums ========================================= -For all below enum names used for configuration of pin use the -``DPLL_PIN_`` prefix. - Values for ``DPLL_A_PIN_STATE`` attribute: - ======================= ======================================== - ``STATE_CONNECTED`` Pin used as active source for a dpll - device or for a parent pin - ``STATE_DISCONNECTED`` Pin disconnected from a dpll device or - from a parent pin - ``STATE_SELECTABLE`` Pin enabled for automatic selection + =============================== ======================================== + ``DPLL_PIN_STATE_CONNECTED`` Pin used as active source for a dpll + device or for a parent pin + ``DPLL_PIN_STATE_DISCONNECTED`` Pin disconnected from a dpll device or + from a parent pin + ``DPLL_PIN_STATE_SELECTABLE`` Pin enabled for automatic selection Values for ``DPLL_A_PIN_DIRECTION`` attribute: - ======================= ============================== - ``DIRECTION_SOURCE`` Pin used as a source of signal - ``DIRECTION_OUTPUT`` Pin used to output signal + ============================= ============================== + ``DPLL_PIN_DIRECTION_SOURCE`` Pin used as a source of signal + ``DPLL_PIN_DIRECTION_OUTPUT`` Pin used to output signal Values for ``DPLL_A_PIN_TYPE`` attributes: - ======================== ======================================== - ``TYPE_MUX`` MUX type pin, connected pins shall have - their own types - ``TYPE_EXT`` External pin - ``TYPE_SYNCE_ETH_PORT`` SyncE on Ethernet port - ``TYPE_INT_OSCILLATOR`` Internal Oscillator (i.e. Holdover with - Atomic Clock as a Source) - ``TYPE_GNSS`` GNSS 1PPS source + ================================ ======================================== + ``DPLL_PIN_TYPE_MUX`` MUX type pin, connected pins shall have + their own types + ``DPLL_PIN_TYPE_EXT`` External pin + ``DPLL_PIN_TYPE_SYNCE_ETH_PORT`` SyncE on Ethernet port + ``DPLL_PIN_TYPE_INT_OSCILLATOR`` Internal Oscillator (i.e. Holdover with + Atomic Clock as a Source) + ``DPLL_PIN_TYPE_GNSS`` GNSS 1PPS source Values for ``DPLL_A_PIN_DPLL_CAPS`` attributes: - ============================= ================================ - ``CAPS_DIRECTION_CAN_CHANGE`` Bit present if direction can change - ``CAPS_PRIORITY_CAN_CHANGE`` Bit present if priority can change - ``CAPS_STATE_CAN_CHANGE`` Bit present if state can change + ====================================== =================================== + ``DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE`` Bit present if direction can change + ``DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE`` Bit present if priority can change + ``DPLL_PIN_CAPS_STATE_CAN_CHANGE`` Bit present if state can change Notifications @@ -323,25 +318,24 @@ Notifications dpll device can provide notifications regarding status changes of the device, i.e. lock status changes, source/output type changes or alarms. -This is the multicast group that is used to notify user-space apps via +There is one multicast group that is used to notify user-space apps via netlink socket: ``DPLL_MCGRP_MONITOR`` -Notifications messages (attrbiutes use ``DPLL_A`` prefix): - - ========================= ========================================== - ``EVENT_DEVICE_CREATE`` event value new dpll device was created - ``ID`` attr internal dpll device ID - ``DEV_NAME`` attr dpll device name - ``BUS_NAME`` attr dpll device bus name - ``EVENT_DEVICE_DELETE`` event value dpll device was deleted - ``ID`` attr dpll device index - ``EVENT_DEVICE_CHANGE`` event value dpll device attribute has - changed - ``ID`` attr modified dpll device ID - ``PIN_IDX`` attr the modified pin index - -Device change event shall consiste of the attribute and the value that -has changed. +Notifications messages: + + ============================== ===================================== + ``DPLL_CMD_DEVICE_CREATE_NTF`` dpll device was created + ``DPLL_CMD_DEVICE_DELETE_NTF`` dpll device was deleted + ``DPLL_CMD_DEVICE_CHANGE_NTF`` dpll defice has changed + ``DPLL_CMD_PIN_CREATE_NTF`` dpll pin was created + ``DPLL_CMD_PIN_DELETE_NTF`` dpll pin was deleted + ``DPLL_CMD_PIN_CHANGE_NTF`` dpll pin has changed + +Events format is the same as for the corresponding get command. +Format of ``DPLL_CMD_DEVICE_`` events is the same as response of +``DPLL_CMD_DEVICE_GET``. +Format of ``DPLL_CMD_PIN_`` events is same as response of +``DPLL_CMD_PIN_GET``. Device driver implementation From 5ce5a754c968cb4b04d1d22cf60c11ff4469d7f9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 19 May 2023 21:34:13 +0200 Subject: [PATCH 58/93] dpll: spec: fix enum names Rename enum attributes name from dplla to dpll_a. Add name for dpll commands enum: dpll_cmd. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 3 ++- include/uapi/linux/dpll.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 6cd7a3c85b51..4ebe07169b1c 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -172,7 +172,7 @@ definitions: attribute-sets: - name: dpll - enum-name: dplla + enum-name: dpll_a attributes: - name: id @@ -308,6 +308,7 @@ attribute-sets: type: u8 operations: + enum-name: dpll_cmd list: - name: device-get diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 511b213b30c7..29e652777818 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -133,7 +133,7 @@ enum dpll_pin_caps { DPLL_PIN_CAPS_STATE_CAN_CHANGE = 4, }; -enum dplla { +enum dpll_a { DPLL_A_ID = 1, DPLL_A_DEV_NAME, DPLL_A_BUS_NAME, @@ -163,7 +163,7 @@ enum dplla { DPLL_A_MAX = (__DPLL_A_MAX - 1) }; -enum { +enum dpll_cmd { DPLL_CMD_DEVICE_GET = 1, DPLL_CMD_DEVICE_SET, DPLL_CMD_DEVICE_CREATE_NTF, From 8e02344d4d0614c88dc877824fec7c6696030a61 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Fri, 19 May 2023 21:42:19 +0200 Subject: [PATCH 59/93] dpll: core: fix enum names The argument of notify functions shall be of 'enum dpll_cmd' type. Fix it. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 5a6dc45a0997..5c9a5e8541d9 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -814,7 +814,7 @@ int dpll_pin_post_dumpit(struct netlink_callback *cb) } static int -dpll_device_event_send(enum dplla event, struct dpll_device *dpll) +dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll) { struct sk_buff *msg; int ret = -EMSGSIZE; @@ -871,7 +871,7 @@ int dpll_device_change_ntf(struct dpll_device *dpll) EXPORT_SYMBOL_GPL(dpll_device_change_ntf); static int -dpll_pin_event_send(enum dplla event, struct dpll_pin *pin) +dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) { struct dpll_pin *pin_verify; struct sk_buff *msg; From 1547d098b62a036d5b3ffcbb14b4041738403aa1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 24 May 2023 11:14:42 +0200 Subject: [PATCH 60/93] ice: fix dpll init error path Fix implementation of error paths in ice_dpll_init. Previously the implementation worked but error paths were not clear for the developers. Fix by providing separated functions for each error encountered during initialization. Fix function descriptions. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 637 +++++++++++++++------- drivers/net/ethernet/intel/ice/ice_dpll.h | 6 +- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 3 files changed, 456 insertions(+), 189 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 236a12b488fa..346f92d4be45 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -6,9 +6,10 @@ #include "ice_trace.h" #include -#define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 -#define ICE_DPLL_LOCK_TRIES 1000 -#define ICE_DPLL_PIN_IDX_INVALID 0xff +#define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50 +#define ICE_DPLL_LOCK_TRIES 1000 +#define ICE_DPLL_PIN_IDX_INVALID 0xff +#define ICE_DPLL_RCLK_NUM_PER_PF 1 /** * dpll_lock_status - map ice cgu states into dpll's subsystem lock status @@ -88,6 +89,7 @@ static void ice_dpll_cb_unlock(struct ice_pf *pf) * * Set requested frequency on a pin. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - error on AQ or wrong pin type given @@ -138,6 +140,7 @@ ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, * * Wraps internal set frequency command on a pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't set in hw @@ -175,6 +178,7 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, * * Wraps internal set frequency command on a pin. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't set in hw @@ -199,6 +203,7 @@ ice_dpll_source_frequency_set(const struct dpll_pin *pin, void *pin_priv, * * Wraps internal set frequency command on a pin. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't set in hw @@ -224,6 +229,7 @@ ice_dpll_output_frequency_set(const struct dpll_pin *pin, void *pin_priv, * * Wraps internal get frequency command of a pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't get from hw @@ -258,6 +264,7 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, * * Wraps internal get frequency command of a source pin. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't get from hw @@ -282,6 +289,7 @@ ice_dpll_source_frequency_get(const struct dpll_pin *pin, void *pin_priv, * * Wraps internal get frequency command of a pin. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - error pin not found or couldn't get from hw @@ -303,6 +311,7 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, * * Enable a pin on both dplls. Store current state in pin->flags. * + * Context: Called under pf->dplls.lock * Return: * * 0 - OK * * negative - error @@ -347,6 +356,7 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, * * Disable a pin on both dplls. Store current state in pin->flags. * + * Context: Called under pf->dplls.lock * Return: * * 0 - OK * * negative - error @@ -391,6 +401,7 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, * holding the pin info. For source pin states are separated for each * dpll, for rclk pins states are separated for each parent. * + * Context: Called under pf->dplls.lock * Return: * * 0 - OK * * negative - error @@ -469,6 +480,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, * @pf: private board structure * @dpll: kernel's dpll_device pointer to be searched * + * Context: Called under pf->dplls.lock * Return: * * pointer if ice_dpll with given device dpll pointer is found * * NULL if not found @@ -492,6 +504,7 @@ static struct ice_dpll * * Internal wrapper for setting the priority in the hardware. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -522,6 +535,7 @@ ice_dpll_hw_source_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, * * Dpll subsystem callback, provides dpll's lock status. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -603,6 +617,7 @@ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, * * Set pin state on a pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - OK or no change required * * negative - error @@ -646,6 +661,7 @@ ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, * * Dpll subsystem callback. Set given state on output type pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - successfully enabled mode * * negative - failed to enable mode @@ -674,6 +690,7 @@ static int ice_dpll_output_state_set(const struct dpll_pin *pin, * * Dpll subsystem callback. Enables given mode on source type pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - successfully enabled mode * * negative - failed to enable mode @@ -703,6 +720,7 @@ static int ice_dpll_source_state_set(const struct dpll_pin *pin, * * Determine pin state set it on a pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failed to get state @@ -754,6 +772,7 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, * * Dpll subsystem callback. Check state of a pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failed to get state @@ -780,6 +799,7 @@ static int ice_dpll_output_state_get(const struct dpll_pin *pin, * * Dpll subsystem callback. Check state of a source pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failed to get state @@ -806,6 +826,7 @@ static int ice_dpll_source_state_get(const struct dpll_pin *pin, * * Dpll subsystem callback. Handler for getting priority of a source pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -842,6 +863,7 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, * * Dpll subsystem callback. Handler for setting priority of a source pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -938,6 +960,7 @@ static int ice_dpll_output_direction(const struct dpll_pin *pin, * * Dpll subsystem callback, set a state of a rclk pin on a parent pin * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -988,6 +1011,7 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, * * dpll subsystem callback, get a state of a recovered clock pin. * + * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure @@ -1057,12 +1081,14 @@ static const struct dpll_device_ops ice_dpll_ops = { }; /** - * ice_dpll_release_info - release memory allocated for pins + * ice_dpll_deinit_info - release memory allocated for pins info * @pf: board private structure * * Release memory allocated for pins by ice_dpll_init_info function. + * + * Context: Called under pf->dplls.lock */ -static void ice_dpll_release_info(struct ice_pf *pf) +static void ice_dpll_deinit_info(struct ice_pf *pf) { kfree(pf->dplls.inputs); pf->dplls.inputs = NULL; @@ -1075,13 +1101,15 @@ static void ice_dpll_release_info(struct ice_pf *pf) } /** - * ice_dpll_release_rclk_pin - release rclk pin from its parents + * ice_dpll_deinit_rclk_pin - release rclk pin resources * @pf: board private structure * - * Deregister from parent pins and release resources in dpll subsystem. + * Deregister rclk pin from parent pins and release resources in dpll subsystem. + * + * Context: Called under pf->dplls.lock */ static void -ice_dpll_release_rclk_pin(struct ice_pf *pf) +ice_dpll_deinit_rclk_pin(struct ice_pf *pf) { struct ice_dpll_pin *rclk = &pf->dplls.rclk; struct ice_vsi *vsi = ice_get_main_vsi(pf); @@ -1092,8 +1120,9 @@ ice_dpll_release_rclk_pin(struct ice_pf *pf) parent = pf->dplls.inputs[rclk->parent_idx[i]].pin; if (!parent) continue; - dpll_pin_on_pin_unregister(parent, rclk->pin, - &ice_dpll_rclk_ops, rclk); + if (!IS_ERR_OR_NULL(rclk->pin)) + dpll_pin_on_pin_unregister(parent, rclk->pin, + &ice_dpll_rclk_ops, rclk); } if (WARN_ON_ONCE(!vsi || !vsi->netdev)) return; @@ -1103,33 +1132,50 @@ ice_dpll_release_rclk_pin(struct ice_pf *pf) } /** - * ice_dpll_release_pins - release pin's from dplls registered in subsystem - * @pf: board private structure - * @dpll_eec: dpll_eec dpll pointer - * @dpll_pps: dpll_pps dpll pointer + * ice_dpll_unregister_pins - unregister pins from a dpll + * @dpll: dpll device pointer * @pins: pointer to pins array - * @count: number of pins * @ops: callback ops registered with the pins - * @cgu: if cgu is present and controlled by this NIC + * @count: number of pins * - * Deregister and free pins of a given array of pins from dpll devices - * registered in dpll subsystem. + * Unregister pins of a given array of pins from given dpll device registered in + * dpll subsystem. + * + * Context: Called under pf->dplls.lock */ static void -ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, - struct dpll_device *dpll_pps, struct ice_dpll_pin *pins, - int count, const struct dpll_pin_ops *ops, bool cgu) +ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, + const struct dpll_pin_ops *ops, int count) { + struct ice_dpll_pin *p; int i; for (i = 0; i < count; i++) { - struct ice_dpll_pin *p = &pins[i]; + p = &pins[i]; + if (p && !IS_ERR_OR_NULL(p->pin)) + dpll_pin_unregister(dpll, p->pin, ops, p); + } +} + +/** + * ice_dpll_release_pins - release pins resources from dpll subsystem + * @pf: board private structure + * @pins: pointer to pins array + * @count: number of pins + * + * Release resources of given pins array in the dpll subsystem. + * + * Context: Called under pf->dplls.lock + */ +static void +ice_dpll_release_pins(struct ice_dpll_pin *pins, int count) +{ + struct ice_dpll_pin *p; + int i; - if (p && !IS_ERR(p->pin)) { - if (cgu && dpll_eec) - dpll_pin_unregister(dpll_eec, p->pin, ops, p); - if (cgu && dpll_pps) - dpll_pin_unregister(dpll_pps, p->pin, ops, p); + for (i = 0; i < count; i++) { + p = &pins[i]; + if (p && !IS_ERR_OR_NULL(p->pin)) { dpll_pin_put(p->pin); p->pin = NULL; } @@ -1137,88 +1183,263 @@ ice_dpll_release_pins(struct ice_pf *pf, struct dpll_device *dpll_eec, } /** - * ice_dpll_init_pins - init pins and register pins with a dplls + * ice_dpll_get_pins - get pins from dpll subsystem * @pf: board private structure + * @pins: pointer to pins array + * @start_idx: get starts from this pin idx value + * @count: number of pins + * @clock_id: clock_id of dpll device + * + * Get pins - allocate - in dpll subsystem, store them in pin field of given + * pins array. + * + * Context: Called under pf->dplls.lock + * Return: + * * 0 - success + * * negative - allocation failure reason + */ +static int +ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins, + int start_idx, int count, u64 clock_id) +{ + int i, ret; + + for (i = 0; i < count; i++) { + pins[i].pin = dpll_pin_get(clock_id, i + start_idx, THIS_MODULE, + &pins[i].prop); + if (IS_ERR(pins[i].pin)) { + ret = PTR_ERR(pins[i].pin); + goto release_pins; + } + } + + return 0; + +release_pins: + ice_dpll_release_pins(pins, i); + return ret; +} + +/** + * ice_dpll_register_pins - register pins with a dpll + * @dpll: dpll pointer to register pins with + * @pins: pointer to pins array + * @ops: callback ops registered with the pins + * @count: number of pins * @cgu: if cgu is present and controlled by this NIC * - * Register source or output pins within given DPLL in a Linux dpll subsystem. + * Register pins of a given array with given dpll in dpll subsystem. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success - * * negative - error + * * negative - registration failure reason */ -static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) +static int +ice_dpll_register_pins(struct dpll_device *dpll, + struct ice_dpll_pin *pins, + const struct dpll_pin_ops *ops, + int count) { - struct device *dev = ice_pf_to_dev(pf); - const struct dpll_pin_ops *ops; - struct ice_dpll_pin *pins; - u32 rclk_idx; int ret, i; - ops = &ice_dpll_source_ops; - pins = pf->dplls.inputs; - for (i = 0; i < pf->dplls.num_inputs; i++) { - pins[i].pin = dpll_pin_get(pf->dplls.clock_id, i, - THIS_MODULE, &pins[i].prop); - if (IS_ERR(pins[i].pin)) - return PTR_ERR(pins[i].pin); - pins[i].pf = pf; - if (cgu) { - ret = dpll_pin_register(pf->dplls.eec.dpll, - pins[i].pin, - ops, &pins[i], NULL); - if (ret) - return ret; - ret = dpll_pin_register(pf->dplls.pps.dpll, - pins[i].pin, - ops, &pins[i], NULL); - if (ret) - return ret; - } + for (i = 0; i < count; i++) { + ret = dpll_pin_register(dpll, pins[i].pin, ops, + &pins[i], NULL); + if (ret) + goto unregister_pins; } + + return 0; + +unregister_pins: + ice_dpll_unregister_pins(dpll, pins, ops, i); + return ret; +} + +/** + * ice_dpll_init_direct_pins - initialize direct pins + * @dpll: dpll pointer to register pins with + * @cgu: if cgu is present and controlled by this NIC + * @pins: pointer to pins array + * @start_idx: on which index shall allocation start in dpll subsystem + * @count: number of pins + * @ops: callback ops registered with the pins + * @first: dpll device pointer + * @second: dpll device pointer + * + * Allocate directly connected pins of a given array in dpll subsystem. + * If cgu is owned register allocated pins with given dplls. + * + * Context: Called under pf->dplls.lock + * Return: + * * 0 - success + * * negative - registration failure reason + */ +static int +ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu, + struct ice_dpll_pin *pins, int start_idx, int count, + const struct dpll_pin_ops *ops, + struct dpll_device *first, struct dpll_device *second) +{ + int ret; + + ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id); + if (ret) + return ret; if (cgu) { - ops = &ice_dpll_output_ops; - pins = pf->dplls.outputs; - for (i = 0; i < pf->dplls.num_outputs; i++) { - pins[i].pin = dpll_pin_get(pf->dplls.clock_id, - i + pf->dplls.num_inputs, - THIS_MODULE, &pins[i].prop); - if (IS_ERR(pins[i].pin)) - return PTR_ERR(pins[i].pin); - pins[i].pf = pf; - ret = dpll_pin_register(pf->dplls.eec.dpll, pins[i].pin, - ops, &pins[i], NULL); - if (ret) - return ret; - ret = dpll_pin_register(pf->dplls.pps.dpll, pins[i].pin, - ops, &pins[i], NULL); - if (ret) - return ret; - } + ret = ice_dpll_register_pins(first, pins, ops, count); + if (ret) + goto release_pins; + ret = ice_dpll_register_pins(second, pins, ops, count); + if (ret) + goto unregister_first; } - rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; - pf->dplls.rclk.pin = dpll_pin_get(pf->dplls.clock_id, rclk_idx, - THIS_MODULE, &pf->dplls.rclk.prop); - if (IS_ERR(pf->dplls.rclk.pin)) - return PTR_ERR(pf->dplls.rclk.pin); - ops = &ice_dpll_rclk_ops; - pf->dplls.rclk.pf = pf; - for (i = 0; i < pf->dplls.rclk.num_parents; i++) { - struct dpll_pin *parent = - pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; - struct ice_vsi *vsi = ice_get_main_vsi(pf); + return 0; + +unregister_first: + ice_dpll_unregister_pins(first, pins, ops, count); +release_pins: + ice_dpll_release_pins(pins, count); + return ret; +} + +/** + * ice_dpll_deinit_direct_pins - deinitialize direct pins + * @cgu: if cgu is present and controlled by this NIC + * @pins: pointer to pins array + * @count: number of pins + * @ops: callback ops registered with the pins + * @first: dpll device pointer + * @second: dpll device pointer + * + * Context: Called under pf->dplls.lock + * If cgu is owned unregister pins from given dplls. + * Release pins resources to the dpll subsystem. + */ +static void +ice_dpll_deinit_direct_pins(bool cgu, struct ice_dpll_pin *pins, int count, + const struct dpll_pin_ops *ops, + struct dpll_device *first, + struct dpll_device *second) +{ + if (cgu) { + ice_dpll_unregister_pins(first, pins, ops, count); + ice_dpll_unregister_pins(second, pins, ops, count); + } + ice_dpll_release_pins(pins, count); +} + +/** + * ice_dpll_init_rclk_pins - initialize recovered clock pin + * @dpll: dpll pointer to register pins with + * @cgu: if cgu is present and controlled by this NIC + * @pins: pointer to pins array + * @start_idx: on which index shall allocation start in dpll subsystem + * @count: number of pins + * @ops: callback ops registered with the pins + * + * Allocate resource for recovered clock pin in dpll subsystem. Register the + * pin with the parents it has in the info. Register pin with the pf's main vsi + * netdev. + * + * Context: Called under pf->dplls.lock + * Return: + * * 0 - success + * * negative - registration failure reason + */ +static int +ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin, + int start_idx, const struct dpll_pin_ops *ops) +{ + struct ice_vsi *vsi = ice_get_main_vsi(pf); + struct device *dev = ice_pf_to_dev(pf); + struct dpll_pin *parent; + int ret, i; + + ret = ice_dpll_get_pins(pf, pin, start_idx, ICE_DPLL_RCLK_NUM_PER_PF, + pf->dplls.clock_id); + if (ret) + return ret; + for (i = 0; i < pf->dplls.rclk.num_parents; i++) { + parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[i]].pin; + if (!parent) { + ret = -ENODEV; + goto unregister_pins; + } ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, ops, &pf->dplls.rclk, dev); if (ret) - return ret; + goto unregister_pins; + } + if (WARN_ON((!vsi || !vsi->netdev))) + return -EINVAL; + netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin); + + return 0; - if (!vsi || !vsi->netdev) - return -EINVAL; - netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin); +unregister_pins: + while (i) { + parent = pf->dplls.inputs[pf->dplls.rclk.parent_idx[--i]].pin; + dpll_pin_on_pin_unregister(parent, pf->dplls.rclk.pin, + &ice_dpll_rclk_ops, &pf->dplls.rclk); } + ice_dpll_release_pins(pin, ICE_DPLL_RCLK_NUM_PER_PF); + return ret; +} + +/** + * ice_dpll_init_pins - init pins and register pins with a dplls + * @pf: board private structure + * @cgu: if cgu is present and controlled by this NIC + * + * Initialize directly connected pf's pins within pf's dplls in a Linux dpll + * subsystem. + * + * Context: Called under pf->dplls.lock + * Return: + * * 0 - success + * * negative - initialization failure reason + */ +static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) +{ + u32 rclk_idx; + int ret; + + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0, + pf->dplls.num_inputs, + &ice_dpll_source_ops, + pf->dplls.eec.dpll, pf->dplls.pps.dpll); + if (ret) + return ret; + if (cgu) { + ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs, + pf->dplls.num_inputs, + pf->dplls.num_outputs, + &ice_dpll_output_ops, + pf->dplls.eec.dpll, + pf->dplls.pps.dpll); + if (ret) + goto deinit_inputs; + } + rclk_idx = pf->dplls.num_inputs + pf->dplls.num_outputs + pf->hw.pf_id; + ret = ice_dpll_init_rclk_pins(pf, &pf->dplls.rclk, rclk_idx, + &ice_dpll_rclk_ops); + if (ret) + goto deinit_outputs; return 0; +deinit_outputs: + ice_dpll_deinit_direct_pins(cgu, pf->dplls.outputs, + pf->dplls.num_outputs, + &ice_dpll_output_ops, pf->dplls.pps.dpll, + pf->dplls.eec.dpll); +deinit_inputs: + ice_dpll_deinit_direct_pins(cgu, pf->dplls.inputs, pf->dplls.num_inputs, + &ice_dpll_source_ops, pf->dplls.pps.dpll, + pf->dplls.eec.dpll); + return ret; } /** @@ -1236,51 +1457,43 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) } /** - * ice_dpll_init_dplls + * ice_dpll_init_dpll - initialize dpll device in dpll subsystem * @pf: board private structure + * @d: dpll to be initialized * @cgu: if cgu is present and controlled by this NIC + * @type: type of dpll being initialized * - * Get dplls instances for this board, if cgu is controlled by this NIC, - * register dpll with callbacks ops + * Allocate dpll instance for this board in dpll subsystem, if cgu is controlled + * by this NIC, register dpll with the callback ops. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success - * * negative - allocation fails + * * negative - initialization failure reason */ -static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) +static int +ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, + enum dpll_type type) { struct device *dev = ice_pf_to_dev(pf); - struct ice_dpll *de = &pf->dplls.eec; - struct ice_dpll *dp = &pf->dplls.pps; - int ret = -ENOMEM; - u64 clock_id; + u64 clock_id = pf->dplls.clock_id; + int ret; - clock_id = pf->dplls.clock_id; - de->dpll = dpll_device_get(clock_id, de->dpll_idx, THIS_MODULE); - if (IS_ERR(de->dpll)) { - ret = PTR_ERR(de->dpll); + d->dpll = dpll_device_get(clock_id, d->dpll_idx, THIS_MODULE); + if (IS_ERR(d->dpll)) { + ret = PTR_ERR(d->dpll); dev_err(ice_pf_to_dev(pf), - "dpll_device_get failed (eec) err=%d\n", ret); + "dpll_device_get failed (%p) err=%d\n", d, ret); return ret; } - de->pf = pf; - dp->dpll = dpll_device_get(clock_id, dp->dpll_idx, THIS_MODULE); - if (IS_ERR(dp->dpll)) { - ret = PTR_ERR(dp->dpll); - dev_err(ice_pf_to_dev(pf), - "dpll_device_get failed (pps) err=%d\n", ret); - return ret; - } - dp->pf = pf; + d->pf = pf; if (cgu) { - ret = dpll_device_register(de->dpll, DPLL_TYPE_EEC, - &ice_dpll_ops, de, dev); - if (ret) - return ret; - ret = dpll_device_register(dp->dpll, DPLL_TYPE_PPS, - &ice_dpll_ops, dp, dev); - if (ret) + ret = dpll_device_register(d->dpll, type, &ice_dpll_ops, + d, dev); + if (ret) { + dpll_device_put(d->dpll); return ret; + } } return 0; @@ -1292,11 +1505,14 @@ static int ice_dpll_init_dplls(struct ice_pf *pf, bool cgu) * @d: pointer to queried dpll device * * Poll current state of dpll from hw and update ice_dpll struct. + * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - AQ failure */ -static int ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) +static int +ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) { struct ice_dpll_pin *p; int ret; @@ -1330,7 +1546,8 @@ static int ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool ini p = &pf->dplls.inputs[d->source_idx]; d->prev_source_idx = ICE_DPLL_PIN_IDX_INVALID; d->source_idx = ICE_DPLL_PIN_IDX_INVALID; - ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); + ret = ice_dpll_pin_state_update(pf, p, + ICE_DPLL_PIN_TYPE_SOURCE); } else if (d->source_idx != d->prev_source_idx) { p = &pf->dplls.inputs[d->prev_source_idx]; ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); @@ -1369,6 +1586,7 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) * @work: pointer to kthread_work structure * * DPLLs periodic worker is responsible for polling state of dpll. + * Context: Holds pf->dplls.lock */ static void ice_dpll_periodic_work(struct kthread_work *work) { @@ -1414,6 +1632,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) * * Create and start DPLLs periodic worker. * + * Context: Called under pf->dplls.lock * Return: * * 0 - success * * negative - create worker failure @@ -1438,87 +1657,126 @@ static int ice_dpll_init_worker(struct ice_pf *pf) } /** - * ice_dpll_release_all - disable support for DPLL and unregister dpll device + * ice_dpll_deinit_pins - deinitialize direct pins * @pf: board private structure - * @cgu: if cgu is controlled by this driver instance + * @cgu: if cgu is controlled by this pf * - * This function handles the cleanup work required from the initialization by - * freeing resources and unregistering the dpll. + * If cgu is owned unregister directly connected pins from the dplls. + * Release resources of directly connected pins from the dpll subsystem. * * Context: Called under pf->dplls.lock */ -static void ice_dpll_release_all(struct ice_pf *pf, bool cgu) +static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) { + struct ice_dpll_pin *outputs = pf->dplls.outputs; + struct ice_dpll_pin *inputs = pf->dplls.inputs; + int num_outputs = pf->dplls.num_outputs; + int num_inputs = pf->dplls.num_inputs; struct ice_dplls *d = &pf->dplls; struct ice_dpll *de = &d->eec; struct ice_dpll *dp = &d->pps; - mutex_lock(&pf->dplls.lock); - ice_dpll_release_rclk_pin(pf); - ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->inputs, - d->num_inputs, &ice_dpll_source_ops, cgu); + ice_dpll_deinit_rclk_pin(pf); if (cgu) { - ice_dpll_release_pins(pf, de->dpll, dp->dpll, d->outputs, - d->num_outputs, - &ice_dpll_output_ops, cgu); + ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_source_ops, + num_inputs); + ice_dpll_unregister_pins(de->dpll, inputs, &ice_dpll_source_ops, + num_inputs); } - ice_dpll_release_info(pf); - if (!IS_ERR(dp->dpll)) { - if (cgu) - dpll_device_unregister(dp->dpll, &ice_dpll_ops, dp); - dpll_device_put(dp->dpll); - dev_dbg(ice_pf_to_dev(pf), "PPS dpll removed\n"); + ice_dpll_release_pins(inputs, num_inputs); + if (cgu) { + ice_dpll_unregister_pins(dp->dpll, outputs, + &ice_dpll_output_ops, num_outputs); + ice_dpll_unregister_pins(de->dpll, outputs, + &ice_dpll_output_ops, num_outputs); + ice_dpll_release_pins(outputs, num_outputs); } +} - if (!IS_ERR(de->dpll)) { +/** + * ice_dpll_deinit_dpll - deinitialize dpll device + * @pf: board private structure + * + * If cgu is owned unregister the dpll from dpll subsystem. + * Release resources of dpll device from dpll subsystem. + * + * Context: Called under pf->dplls.lock + */ +static void +ice_dpll_deinit_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu) +{ + if (!IS_ERR(d->dpll)) { if (cgu) - dpll_device_unregister(de->dpll, &ice_dpll_ops, de); - dpll_device_put(de->dpll); - dev_dbg(ice_pf_to_dev(pf), "EEC dpll removed\n"); + dpll_device_unregister(d->dpll, &ice_dpll_ops, d); + dpll_device_put(d->dpll); + dev_dbg(ice_pf_to_dev(pf), "(%p) dpll removed\n", d); } +} - if (cgu) { - kthread_cancel_delayed_work_sync(&d->work); - if (!IS_ERR_OR_NULL(d->kworker)) { - kthread_destroy_worker(d->kworker); - d->kworker = NULL; - dev_dbg(ice_pf_to_dev(pf), "DPLLs worker removed\n"); - } +/** + * ice_dpll_deinit_worker - deinitialize dpll kworker + * @pf: board private structure + * + * Stop dpll's kworker, release it's resources. + * + * Context: Called under pf->dplls.lock + */ +static void ice_dpll_deinit_worker(struct ice_pf *pf) +{ + struct ice_dplls *d = &pf->dplls; + + kthread_cancel_delayed_work_sync(&d->work); + if (!IS_ERR_OR_NULL(d->kworker)) { + kthread_destroy_worker(d->kworker); + d->kworker = NULL; + dev_dbg(ice_pf_to_dev(pf), "DPLLs worker removed\n"); } - mutex_unlock(&pf->dplls.lock); } /** - * ice_dpll_release - Disable the driver/HW support for DPLLs and unregister + * ice_dpll_deinit - Disable the driver/HW support for dpll subsystem * the dpll device. * @pf: board private structure * - * Handles the cleanup work required after dpll initialization, - * freeing resources and unregistering the dpll. + * Handles the cleanup work required after dpll initialization,freeing resources + * and unregistering the dpll, pin and all resources used for handling them. + * + * Context: Function holds pf->dplls.lock mutex. */ -void ice_dpll_release(struct ice_pf *pf) +void ice_dpll_deinit(struct ice_pf *pf) { + bool cgu = ice_is_feature_supported(pf, ICE_F_CGU); + if (test_bit(ICE_FLAG_DPLL, pf->flags)) { - ice_dpll_release_all(pf, - ice_is_feature_supported(pf, ICE_F_CGU)); - mutex_destroy(&pf->dplls.lock); + mutex_lock(&pf->dplls.lock); + ice_dpll_deinit_pins(pf, cgu); + ice_dpll_deinit_info(pf); + ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu); + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu); + if (cgu) + ice_dpll_deinit_worker(pf); clear_bit(ICE_FLAG_DPLL, pf->flags); + mutex_unlock(&pf->dplls.lock); + mutex_destroy(&pf->dplls.lock); } } /** - * ice_dpll_init_direct_pins - initializes source or output pins information + * ice_dpll_init_info_direct_pins - initializes direct pins info * @pf: board private structure * @pin_type: type of pins being initialized * - * Init information about input or output pins, cache them in pins struct. + * Init information for directly connected pins, cache them in pf's pins + * structures. * + * Context: Function initializes and holds pf->dplls.lock mutex. * Return: * * 0 - success - * * negative - init failure + * * negative - init failure reason */ static int -ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) +ice_dpll_init_info_direct_pins(struct ice_pf *pf, + enum ice_dpll_pin_type pin_type) { struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps; int num_pins, i, ret = -EINVAL; @@ -1565,6 +1823,7 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) pins[i].prop.freq_supported = ice_cgu_get_pin_freq_supp(hw, i, input, &freq_supp_num); pins[i].prop.freq_supported_num = freq_supp_num; + pins[i].pf = pf; } return ret; @@ -1579,7 +1838,7 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) * * Return: * * 0 - success - * * negative - init failure + * * negative - init failure reason */ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) { @@ -1589,6 +1848,7 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) pin->prop.label = dev_name(dev); pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; pin->prop.capabilities |= DPLL_PIN_CAPS_STATE_CAN_CHANGE; + pin->pf = pf; return ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); @@ -1599,11 +1859,11 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) * @pf: board private structure * @pin_type: type of pins being initialized * - * Wraps functions for pin inti. + * Wraps functions for pin initialization. * * Return: * * 0 - success - * * negative - init failure + * * negative - init failure reason */ static int ice_dpll_init_pins_info(struct ice_pf *pf, @@ -1611,9 +1871,8 @@ ice_dpll_init_pins_info(struct ice_pf *pf, { switch (pin_type) { case ICE_DPLL_PIN_TYPE_SOURCE: - return ice_dpll_init_direct_pins(pf, pin_type); case ICE_DPLL_PIN_TYPE_OUTPUT: - return ice_dpll_init_direct_pins(pf, pin_type); + return ice_dpll_init_info_direct_pins(pf, pin_type); case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: return ice_dpll_init_rclk_pin(pf); default: @@ -1630,7 +1889,7 @@ ice_dpll_init_pins_info(struct ice_pf *pf, * * Return: * * 0 - success - * * negative - error + * * negative - init failure reason */ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) { @@ -1671,17 +1930,17 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_SOURCE); if (ret) - goto release_info; + goto deinit_info; if (cgu) { alloc_size = sizeof(*d->outputs) * d->num_outputs; d->outputs = kzalloc(alloc_size, GFP_KERNEL); if (!d->outputs) - goto release_info; + goto deinit_info; ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT); if (ret) - goto release_info; + goto deinit_info; } ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, @@ -1700,26 +1959,26 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) return 0; -release_info: +deinit_info: dev_err(ice_pf_to_dev(pf), "%s - fail: d->inputs:%p, de->input_prio:%p, dp->input_prio:%p, d->outputs:%p\n", __func__, d->inputs, de->input_prio, dp->input_prio, d->outputs); - ice_dpll_release_info(pf); + ice_dpll_deinit_info(pf); return ret; } /** - * ice_dpll_init - initialize dplls support + * ice_dpll_init - initialize support for dpll subsystem * @pf: board private structure * - * Set up the device dplls registering them and pins connected within Linux dpll + * Set up the device dplls, register them and pins connected within Linux dpll * subsystem. Allow userpsace to obtain state of DPLL and handling of DPLL * configuration requests. * * Return: * * 0 - success - * * negative - init failure + * * negative - init failure reason */ int ice_dpll_init(struct ice_pf *pf) { @@ -1731,30 +1990,42 @@ int ice_dpll_init(struct ice_pf *pf) mutex_lock(&d->lock); err = ice_dpll_init_info(pf, cgu_present); if (err) - goto release; - err = ice_dpll_init_dplls(pf, cgu_present); + goto err_exit; + err = ice_dpll_init_dpll(pf, &pf->dplls.eec, cgu_present, + DPLL_TYPE_EEC); + if (err) + goto deinit_info; + err = ice_dpll_init_dpll(pf, &pf->dplls.pps, cgu_present, + DPLL_TYPE_PPS); if (err) - goto release; + goto deinit_eec; err = ice_dpll_init_pins(pf, cgu_present); if (err) - goto release; + goto deinit_pps; set_bit(ICE_FLAG_DPLL, pf->flags); if (cgu_present) { err = ice_dpll_init_worker(pf); if (err) - goto release; + goto deinit_pins; } mutex_unlock(&d->lock); dev_info(ice_pf_to_dev(pf), "DPLLs init successful\n"); return err; -release: - ice_dpll_release_all(pf, cgu_present); +deinit_pins: + ice_dpll_deinit_pins(pf, cgu_present); +deinit_pps: + ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu_present); +deinit_eec: + ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu_present); +deinit_info: + ice_dpll_deinit_info(pf); +err_exit: clear_bit(ICE_FLAG_DPLL, pf->flags); mutex_unlock(&d->lock); mutex_destroy(&d->lock); - dev_warn(ice_pf_to_dev(pf), "DPLLs init failure\n"); + dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:\n"); return err; } diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index 1f6b1e0268e4..3b055d43a559 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -97,10 +97,6 @@ struct ice_dplls { int ice_dpll_init(struct ice_pf *pf); -void ice_dpll_release(struct ice_pf *pf); - -int ice_dpll_rclk_init(struct ice_pf *pf); - -void ice_dpll_rclk_release(struct ice_pf *pf); +void ice_dpll_deinit(struct ice_pf *pf); #endif diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 95aa06a20893..ba5f3bc9075a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4627,7 +4627,7 @@ static void ice_deinit_features(struct ice_pf *pf) ice_ptp_release(pf); if (ice_is_feature_supported(pf, ICE_F_PHY_RCLK) || ice_is_feature_supported(pf, ICE_F_CGU)) - ice_dpll_release(pf); + ice_dpll_deinit(pf); } static void ice_init_wakeup(struct ice_pf *pf) From 12eb61f7bf3e7b51e19ac8a5ad0eeb9a1ca42113 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 24 May 2023 11:22:46 +0200 Subject: [PATCH 61/93] ice: fix dpll pins naming scheme Rename 'source' to 'input' as it is opposite of 'output', previous naming 'source' shall have 'sink' counterpart, but 'input'/'output' seems a better fit for explaining the pins existence reason. Fix function definition alignment. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 309 +++++++++++----------- drivers/net/ethernet/intel/ice/ice_dpll.h | 16 +- 2 files changed, 157 insertions(+), 168 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 346f92d4be45..bf7712ca3cd5 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -28,18 +28,18 @@ ice_dpll_status[__DPLL_LOCK_STATUS_MAX] = { */ enum ice_dpll_pin_type { ICE_DPLL_PIN_INVALID = 0, - ICE_DPLL_PIN_TYPE_SOURCE, + ICE_DPLL_PIN_TYPE_INPUT, ICE_DPLL_PIN_TYPE_OUTPUT, - ICE_DPLL_PIN_TYPE_RCLK_SOURCE, + ICE_DPLL_PIN_TYPE_RCLK_INPUT, }; /** * pin_type_name - string names of ice pin types */ static const char * const pin_type_name[] = { - [ICE_DPLL_PIN_TYPE_SOURCE] = "source", + [ICE_DPLL_PIN_TYPE_INPUT] = "input", [ICE_DPLL_PIN_TYPE_OUTPUT] = "output", - [ICE_DPLL_PIN_TYPE_RCLK_SOURCE] = "rclk-source", + [ICE_DPLL_PIN_TYPE_RCLK_INPUT] = "rclk-input", }; /** @@ -96,13 +96,13 @@ static void ice_dpll_cb_unlock(struct ice_pf *pf) */ static int ice_dpll_pin_freq_set(struct ice_pf *pf, struct ice_dpll_pin *pin, - const enum ice_dpll_pin_type pin_type, const u32 freq) + enum ice_dpll_pin_type pin_type, const u32 freq) { int ret = -EINVAL; u8 flags; switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: flags = ICE_AQC_SET_CGU_IN_CFG_FLG1_UPDATE_FREQ; ret = ice_aq_set_input_pin_cfg(&pf->hw, pin->idx, flags, pin->flags[0], freq, 0); @@ -150,7 +150,7 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, const u32 frequency, struct netlink_ext_ack *extack, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; @@ -168,7 +168,7 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, } /** - * ice_dpll_source_frequency_set - source pin callback for set frequency + * ice_dpll_input_frequency_set - input pin callback for set frequency * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: pointer to dpll @@ -184,12 +184,12 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv, * * negative - error pin not found or couldn't set in hw */ static int -ice_dpll_source_frequency_set(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, void *dpll_priv, - u64 frequency, struct netlink_ext_ack *extack) +ice_dpll_input_frequency_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 frequency, struct netlink_ext_ack *extack) { return ice_dpll_frequency_set(pin, pin_priv, dpll, dpll_priv, frequency, - extack, ICE_DPLL_PIN_TYPE_SOURCE); + extack, ICE_DPLL_PIN_TYPE_INPUT); } /** @@ -238,7 +238,7 @@ static int ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, u64 *frequency, struct netlink_ext_ack *extack, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; @@ -254,7 +254,7 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, } /** - * ice_dpll_source_frequency_get - source pin callback for get frequency + * ice_dpll_input_frequency_get - input pin callback for get frequency * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: pointer to dpll @@ -262,7 +262,7 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, * @frequency: on success holds pin's frequency * @extack: error reporting * - * Wraps internal get frequency command of a source pin. + * Wraps internal get frequency command of a input pin. * * Context: Called under pf->dplls.lock * Return: @@ -270,12 +270,12 @@ ice_dpll_frequency_get(const struct dpll_pin *pin, void *pin_priv, * * negative - error pin not found or couldn't get from hw */ static int -ice_dpll_source_frequency_get(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, void *dpll_priv, - u64 *frequency, struct netlink_ext_ack *extack) +ice_dpll_input_frequency_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u64 *frequency, struct netlink_ext_ack *extack) { return ice_dpll_frequency_get(pin, pin_priv, dpll, dpll_priv, frequency, - extack, ICE_DPLL_PIN_TYPE_SOURCE); + extack, ICE_DPLL_PIN_TYPE_INPUT); } /** @@ -318,13 +318,13 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv, */ static int ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { int ret = -EINVAL; u8 flags = 0; switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_INPUT_EN; @@ -369,7 +369,7 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, u8 flags = 0; switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: if (pin->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) flags |= ICE_AQC_SET_CGU_IN_CFG_FLG2_ESYNC_EN; ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0); @@ -398,7 +398,7 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, * @pin_type: type of pin being updated * * Determine pin current state and frequency, then update struct - * holding the pin info. For source pin states are separated for each + * holding the pin info. For input pin states are separated for each * dpll, for rclk pins states are separated for each parent. * * Context: Called under pf->dplls.lock @@ -408,23 +408,23 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct ice_dpll_pin *pin, */ int ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { int ret = -EINVAL; switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL, NULL, &pin->flags[0], &pin->freq, NULL); if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) { if (pin->pin) { pin->state[pf->dplls.eec.dpll_idx] = - pin->pin == pf->dplls.eec.active_source ? + pin->pin == pf->dplls.eec.active_input ? DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_SELECTABLE; pin->state[pf->dplls.pps.dpll_idx] = - pin->pin == pf->dplls.pps.active_source ? + pin->pin == pf->dplls.pps.active_input ? DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_SELECTABLE; } else { @@ -449,7 +449,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin, else pin->state[0] = DPLL_PIN_STATE_DISCONNECTED; break; - case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: + case ICE_DPLL_PIN_TYPE_RCLK_INPUT: u8 parent, port_num = ICE_AQC_SET_PHY_REC_CLK_OUT_CURR_PORT; for (parent = 0; parent < pf->dplls.rclk.num_parents; @@ -496,7 +496,7 @@ static struct ice_dpll } /** - * ice_dpll_hw_source_prio_set - set source priority value in hardware + * ice_dpll_hw_input_prio_set - set input priority value in hardware * @pf: board private structure * @dpll: ice dpll pointer * @pin: ice pin pointer @@ -510,8 +510,8 @@ static struct ice_dpll * * negative - failure */ static int -ice_dpll_hw_source_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, - struct ice_dpll_pin *pin, const u32 prio) +ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, + struct ice_dpll_pin *pin, const u32 prio) { int ret; @@ -596,7 +596,7 @@ static int ice_dpll_mode_get(const struct dpll_device *dpll, void *priv, * * false - mode is not supported */ static bool ice_dpll_mode_supported(const struct dpll_device *dpll, void *priv, - const enum dpll_mode mode, + enum dpll_mode mode, struct netlink_ext_ack *extack) { if (mode == DPLL_MODE_AUTOMATIC) @@ -626,7 +626,7 @@ static int ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, bool enable, struct netlink_ext_ack *extack, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; @@ -666,12 +666,11 @@ ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv, * * 0 - successfully enabled mode * * negative - failed to enable mode */ -static int ice_dpll_output_state_set(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - const enum dpll_pin_state state, - struct netlink_ext_ack *extack) +static int +ice_dpll_output_state_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; @@ -680,7 +679,7 @@ static int ice_dpll_output_state_set(const struct dpll_pin *pin, } /** - * ice_dpll_source_state_set - enable/disable source pin on dpll levice + * ice_dpll_input_state_set - enable/disable input pin on dpll levice * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: dpll being configured @@ -688,24 +687,23 @@ static int ice_dpll_output_state_set(const struct dpll_pin *pin, * @state: state of pin to be set * @extack: error reporting * - * Dpll subsystem callback. Enables given mode on source type pin. + * Dpll subsystem callback. Enables given mode on input type pin. * * Context: Acquires pf->dplls.lock * Return: * * 0 - successfully enabled mode * * negative - failed to enable mode */ -static int ice_dpll_source_state_set(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - const enum dpll_pin_state state, - struct netlink_ext_ack *extack) +static int +ice_dpll_input_state_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) { bool enable = state == DPLL_PIN_STATE_SELECTABLE ? true : false; return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable, - extack, ICE_DPLL_PIN_TYPE_SOURCE); + extack, ICE_DPLL_PIN_TYPE_INPUT); } /** @@ -730,7 +728,7 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, const struct dpll_device *dpll, void *dpll_priv, enum dpll_pin_state *state, struct netlink_ext_ack *extack, - const enum ice_dpll_pin_type pin_type) + enum ice_dpll_pin_type pin_type) { struct ice_pf *pf = ((struct ice_dpll *)dpll_priv)->pf; struct ice_dpll_pin *p = pin_priv; @@ -746,7 +744,7 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_pin_state_update(pf, p, pin_type); if (ret) goto unlock; - if (pin_type == ICE_DPLL_PIN_TYPE_SOURCE) + if (pin_type == ICE_DPLL_PIN_TYPE_INPUT) *state = p->state[d->dpll_idx]; else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT) *state = p->state[0]; @@ -777,19 +775,18 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv, * * 0 - success * * negative - failed to get state */ -static int ice_dpll_output_state_get(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - enum dpll_pin_state *state, - struct netlink_ext_ack *extack) +static int +ice_dpll_output_state_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) { return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, extack, ICE_DPLL_PIN_TYPE_OUTPUT); } /** - * ice_dpll_source_state_get - get source pin state on dpll device + * ice_dpll_input_state_get - get input pin state on dpll device * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: registered dpll pointer @@ -797,44 +794,43 @@ static int ice_dpll_output_state_get(const struct dpll_pin *pin, * @state: on success holds state of the pin * @extack: error reporting * - * Dpll subsystem callback. Check state of a source pin. + * Dpll subsystem callback. Check state of a input pin. * * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failed to get state */ -static int ice_dpll_source_state_get(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - enum dpll_pin_state *state, - struct netlink_ext_ack *extack) +static int +ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) { return ice_dpll_pin_state_get(pin, pin_priv, dpll, dpll_priv, state, - extack, ICE_DPLL_PIN_TYPE_SOURCE); + extack, ICE_DPLL_PIN_TYPE_INPUT); } /** - * ice_dpll_source_prio_get - get dpll's source prio + * ice_dpll_input_prio_get - get dpll's input prio * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: registered dpll pointer * @dpll_priv: private data pointer passed on dpll registration - * @prio: on success - returns source priority on dpll + * @prio: on success - returns input priority on dpll * @extack: error reporting * - * Dpll subsystem callback. Handler for getting priority of a source pin. + * Dpll subsystem callback. Handler for getting priority of a input pin. * * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure */ -static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, u32 *prio, - struct netlink_ext_ack *extack) +static int +ice_dpll_input_prio_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 *prio, struct netlink_ext_ack *extack) { struct ice_dpll_pin *p = pin_priv; struct ice_dpll *d = dpll_priv; @@ -853,25 +849,25 @@ static int ice_dpll_source_prio_get(const struct dpll_pin *pin, void *pin_priv, } /** - * ice_dpll_source_prio_set - set dpll source prio + * ice_dpll_input_prio_set - set dpll input prio * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: registered dpll pointer * @dpll_priv: private data pointer passed on dpll registration - * @prio: source priority to be set on dpll + * @prio: input priority to be set on dpll * @extack: error reporting * - * Dpll subsystem callback. Handler for setting priority of a source pin. + * Dpll subsystem callback. Handler for setting priority of a input pin. * * Context: Acquires pf->dplls.lock * Return: * * 0 - success * * negative - failure */ -static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, u32 prio, - struct netlink_ext_ack *extack) +static int +ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + u32 prio, struct netlink_ext_ack *extack) { struct ice_dpll_pin *p = pin_priv; struct ice_dpll *d = dpll_priv; @@ -887,7 +883,7 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, ret = ice_dpll_cb_lock(pf); if (ret) return ret; - ret = ice_dpll_hw_source_prio_set(pf, d, p, prio); + ret = ice_dpll_hw_input_prio_set(pf, d, p, prio); if (ret) NL_SET_ERR_MSG_FMT(extack, "unable to set prio: %u", prio); ice_dpll_cb_unlock(pf); @@ -898,25 +894,24 @@ static int ice_dpll_source_prio_set(const struct dpll_pin *pin, void *pin_priv, } /** - * ice_dpll_source_direction - callback for get source pin direction + * ice_dpll_input_direction - callback for get input pin direction * @pin: pointer to a pin * @pin_priv: private data pointer passed on pin registration * @dpll: registered dpll pointer * @dpll_priv: private data pointer passed on dpll registration - * @direction: holds source pin direction + * @direction: holds input pin direction * @extack: error reporting * - * Dpll subsystem callback. Handler for getting direction of a source pin. + * Dpll subsystem callback. Handler for getting direction of a input pin. * * Return: * * 0 - success */ -static int ice_dpll_source_direction(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - enum dpll_pin_direction *direction, - struct netlink_ext_ack *extack) +static int +ice_dpll_input_direction(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) { *direction = DPLL_PIN_DIRECTION_SOURCE; @@ -937,12 +932,11 @@ static int ice_dpll_source_direction(const struct dpll_pin *pin, * Return: * * 0 - success */ -static int ice_dpll_output_direction(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_device *dpll, - void *dpll_priv, - enum dpll_pin_direction *direction, - struct netlink_ext_ack *extack) +static int +ice_dpll_output_direction(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_device *dpll, void *dpll_priv, + enum dpll_pin_direction *direction, + struct netlink_ext_ack *extack) { *direction = DPLL_PIN_DIRECTION_OUTPUT; @@ -965,12 +959,12 @@ static int ice_dpll_output_direction(const struct dpll_pin *pin, * * 0 - success * * negative - failure */ -static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_pin *parent_pin, - void *parent_pin_priv, - const enum dpll_pin_state state, - struct netlink_ext_ack *extack) +static int +ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *parent_pin, + void *parent_pin_priv, + enum dpll_pin_state state, + struct netlink_ext_ack *extack) { bool enable = state == DPLL_PIN_STATE_CONNECTED ? true : false; struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; @@ -1016,12 +1010,12 @@ static int ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, * * 0 - success * * negative - failure */ -static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, - void *pin_priv, - const struct dpll_pin *parent_pin, - void *parent_pin_priv, - enum dpll_pin_state *state, - struct netlink_ext_ack *extack) +static int +ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv, + const struct dpll_pin *parent_pin, + void *parent_pin_priv, + enum dpll_pin_state *state, + struct netlink_ext_ack *extack) { struct ice_dpll_pin *p = pin_priv, *parent = parent_pin_priv; struct ice_pf *pf = p->pf; @@ -1035,7 +1029,7 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, if (hw_idx >= pf->dplls.num_inputs) goto unlock; - ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + ret = ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_RCLK_INPUT); if (ret) goto unlock; @@ -1053,17 +1047,17 @@ static int ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, static const struct dpll_pin_ops ice_dpll_rclk_ops = { .state_on_pin_set = ice_dpll_rclk_state_on_pin_set, .state_on_pin_get = ice_dpll_rclk_state_on_pin_get, - .direction_get = ice_dpll_source_direction, + .direction_get = ice_dpll_input_direction, }; -static const struct dpll_pin_ops ice_dpll_source_ops = { - .frequency_get = ice_dpll_source_frequency_get, - .frequency_set = ice_dpll_source_frequency_set, - .state_on_dpll_get = ice_dpll_source_state_get, - .state_on_dpll_set = ice_dpll_source_state_set, - .prio_get = ice_dpll_source_prio_get, - .prio_set = ice_dpll_source_prio_set, - .direction_get = ice_dpll_source_direction, +static const struct dpll_pin_ops ice_dpll_input_ops = { + .frequency_get = ice_dpll_input_frequency_get, + .frequency_set = ice_dpll_input_frequency_set, + .state_on_dpll_get = ice_dpll_input_state_get, + .state_on_dpll_set = ice_dpll_input_state_set, + .prio_get = ice_dpll_input_prio_get, + .prio_set = ice_dpll_input_prio_set, + .direction_get = ice_dpll_input_direction, }; static const struct dpll_pin_ops ice_dpll_output_ops = { @@ -1108,8 +1102,7 @@ static void ice_dpll_deinit_info(struct ice_pf *pf) * * Context: Called under pf->dplls.lock */ -static void -ice_dpll_deinit_rclk_pin(struct ice_pf *pf) +static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf) { struct ice_dpll_pin *rclk = &pf->dplls.rclk; struct ice_vsi *vsi = ice_get_main_vsi(pf); @@ -1167,8 +1160,7 @@ ice_dpll_unregister_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, * * Context: Called under pf->dplls.lock */ -static void -ice_dpll_release_pins(struct ice_dpll_pin *pins, int count) +static void ice_dpll_release_pins(struct ice_dpll_pin *pins, int count) { struct ice_dpll_pin *p; int i; @@ -1236,10 +1228,8 @@ ice_dpll_get_pins(struct ice_pf *pf, struct ice_dpll_pin *pins, * * negative - registration failure reason */ static int -ice_dpll_register_pins(struct dpll_device *dpll, - struct ice_dpll_pin *pins, - const struct dpll_pin_ops *ops, - int count) +ice_dpll_register_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, + const struct dpll_pin_ops *ops, int count) { int ret, i; @@ -1409,7 +1399,7 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0, pf->dplls.num_inputs, - &ice_dpll_source_ops, + &ice_dpll_input_ops, pf->dplls.eec.dpll, pf->dplls.pps.dpll); if (ret) return ret; @@ -1437,7 +1427,7 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu) pf->dplls.eec.dpll); deinit_inputs: ice_dpll_deinit_direct_pins(cgu, pf->dplls.inputs, pf->dplls.num_inputs, - &ice_dpll_source_ops, pf->dplls.pps.dpll, + &ice_dpll_input_ops, pf->dplls.pps.dpll, pf->dplls.eec.dpll); return ret; } @@ -1518,12 +1508,12 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) int ret; ret = ice_get_cgu_state(&pf->hw, d->dpll_idx, d->prev_dpll_state, - &d->source_idx, &d->ref_state, &d->eec_mode, + &d->input_idx, &d->ref_state, &d->eec_mode, &d->phase_offset, &d->dpll_state); dev_dbg(ice_pf_to_dev(pf), "update dpll=%d, prev_src_idx:%u, src_idx:%u, state:%d, prev:%d\n", - d->dpll_idx, d->prev_source_idx, d->source_idx, + d->dpll_idx, d->prev_input_idx, d->input_idx, d->dpll_state, d->prev_dpll_state); if (ret) { dev_err(ice_pf_to_dev(pf), @@ -1535,26 +1525,26 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init) if (init) { if (d->dpll_state == ICE_CGU_STATE_LOCKED && d->dpll_state == ICE_CGU_STATE_LOCKED_HO_ACQ) - d->active_source = pf->dplls.inputs[d->source_idx].pin; - p = &pf->dplls.inputs[d->source_idx]; + d->active_input = pf->dplls.inputs[d->input_idx].pin; + p = &pf->dplls.inputs[d->input_idx]; return ice_dpll_pin_state_update(pf, p, - ICE_DPLL_PIN_TYPE_SOURCE); + ICE_DPLL_PIN_TYPE_INPUT); } if (d->dpll_state == ICE_CGU_STATE_HOLDOVER || d->dpll_state == ICE_CGU_STATE_FREERUN) { - d->active_source = NULL; - p = &pf->dplls.inputs[d->source_idx]; - d->prev_source_idx = ICE_DPLL_PIN_IDX_INVALID; - d->source_idx = ICE_DPLL_PIN_IDX_INVALID; + d->active_input = NULL; + p = &pf->dplls.inputs[d->input_idx]; + d->prev_input_idx = ICE_DPLL_PIN_IDX_INVALID; + d->input_idx = ICE_DPLL_PIN_IDX_INVALID; ret = ice_dpll_pin_state_update(pf, p, - ICE_DPLL_PIN_TYPE_SOURCE); - } else if (d->source_idx != d->prev_source_idx) { - p = &pf->dplls.inputs[d->prev_source_idx]; - ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); - p = &pf->dplls.inputs[d->source_idx]; - d->active_source = p->pin; - ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_SOURCE); - d->prev_source_idx = d->source_idx; + ICE_DPLL_PIN_TYPE_INPUT); + } else if (d->input_idx != d->prev_input_idx) { + p = &pf->dplls.inputs[d->prev_input_idx]; + ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_INPUT); + p = &pf->dplls.inputs[d->input_idx]; + d->active_input = p->pin; + ice_dpll_pin_state_update(pf, p, ICE_DPLL_PIN_TYPE_INPUT); + d->prev_input_idx = d->input_idx; } return ret; @@ -1572,12 +1562,12 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) d->prev_dpll_state = d->dpll_state; dpll_device_change_ntf(d->dpll); } - if (d->prev_source != d->active_source) { - if (d->prev_source) - dpll_pin_change_ntf(d->prev_source); - d->prev_source = d->active_source; - if (d->active_source) - dpll_pin_change_ntf(d->active_source); + if (d->prev_input != d->active_input) { + if (d->prev_input) + dpll_pin_change_ntf(d->prev_input); + d->prev_input = d->active_input; + if (d->active_input) + dpll_pin_change_ntf(d->active_input); } } @@ -1678,9 +1668,9 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu) ice_dpll_deinit_rclk_pin(pf); if (cgu) { - ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_source_ops, + ice_dpll_unregister_pins(dp->dpll, inputs, &ice_dpll_input_ops, num_inputs); - ice_dpll_unregister_pins(de->dpll, inputs, &ice_dpll_source_ops, + ice_dpll_unregister_pins(de->dpll, inputs, &ice_dpll_input_ops, num_inputs); } ice_dpll_release_pins(inputs, num_inputs); @@ -1786,7 +1776,7 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, bool input; switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: pins = pf->dplls.inputs; num_pins = pf->dplls.num_inputs; input = true; @@ -1851,7 +1841,7 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) pin->pf = pf; return ice_dpll_pin_state_update(pf, pin, - ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + ICE_DPLL_PIN_TYPE_RCLK_INPUT); } /** @@ -1866,14 +1856,13 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) * * negative - init failure reason */ static int -ice_dpll_init_pins_info(struct ice_pf *pf, - const enum ice_dpll_pin_type pin_type) +ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) { switch (pin_type) { - case ICE_DPLL_PIN_TYPE_SOURCE: + case ICE_DPLL_PIN_TYPE_INPUT: case ICE_DPLL_PIN_TYPE_OUTPUT: return ice_dpll_init_info_direct_pins(pf, pin_type); - case ICE_DPLL_PIN_TYPE_RCLK_SOURCE: + case ICE_DPLL_PIN_TYPE_RCLK_INPUT: return ice_dpll_init_rclk_pin(pf); default: return -EINVAL; @@ -1928,7 +1917,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) if (!dp->input_prio) return -ENOMEM; - ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_SOURCE); + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); if (ret) goto deinit_info; @@ -1949,7 +1938,7 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) return ret; for (i = 0; i < pf->dplls.rclk.num_parents; i++) pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; - ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_SOURCE); + ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); if (ret) return ret; diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h index 3b055d43a559..287892825deb 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.h +++ b/drivers/net/ethernet/intel/ice/ice_dpll.h @@ -36,31 +36,31 @@ struct ice_dpll_pin { * @dpll: pointer to dpll dev * @pf: pointer to pf, which has registered the dpll_device * @dpll_idx: index of dpll on the NIC - * @source_idx: source currently selected - * @prev_source_idx: source previously selected + * @input_idx: currently selected input index + * @prev_input_idx: previously selected input index * @ref_state: state of dpll reference signals * @eec_mode: eec_mode dpll is configured for * @phase_offset: phase delay of a dpll * @input_prio: priorities of each input * @dpll_state: current dpll sync state * @prev_dpll_state: last dpll sync state - * @active_source: pointer to active source pin - * @prev_source: pointer to previous active source pin + * @active_input: pointer to active input pin + * @prev_input: pointer to previous active input pin */ struct ice_dpll { struct dpll_device *dpll; struct ice_pf *pf; int dpll_idx; - u8 source_idx; - u8 prev_source_idx; + u8 input_idx; + u8 prev_input_idx; u8 ref_state; u8 eec_mode; s64 phase_offset; u8 *input_prio; enum ice_cgu_state dpll_state; enum ice_cgu_state prev_dpll_state; - struct dpll_pin *active_source; - struct dpll_pin *prev_source; + struct dpll_pin *active_input; + struct dpll_pin *prev_input; }; /** ice_dplls - store info required for CCU (clock controlling unit) From 5579f1c2ac4d1c8aacde39498e1f94064103eb7c Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 30 May 2023 10:58:45 +0200 Subject: [PATCH 62/93] dpll: spec: rename pin-idx to pin-id, remove pin-parent-idx, device dpll device is identified by DPLL_A_ID, now pin is identified with similar name DPLL_A_PIN_ID (consistency). DPLL_PIN_PARENT_IDX is removed as it is not needed. It was used to target a pin parent, but now we will use a DPLL_A_PIN_PARENT nested attribute which encloses either DPLL_A_ID or DPLL_A_PIN_ID, depending where it is connected. Removed DPLL_A_DEVICE nested attribute as it is replaced by DPLL_A_PIN_PARENT. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 59 ++++++++++----------------- drivers/dpll/dpll_nl.c | 24 +++++++---- drivers/dpll/dpll_nl.h | 3 ++ include/uapi/linux/dpll.h | 4 +- 4 files changed, 43 insertions(+), 47 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 4ebe07169b1c..b062bce8b864 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -208,7 +208,7 @@ attribute-sets: type: u8 enum: type - - name: pin-idx + name: pin-id type: u32 - name: pin-label @@ -247,33 +247,41 @@ attribute-sets: type: nest multi-attr: true nested-attributes: pin-parent - - - name: pin-parent-idx - type: u32 - name: pin-rclk-device type: string - name: pin-dpll-caps type: u32 - - - name: device - type: nest - multi-attr: true - nested-attributes: device - name: pin-parent subset-of: dpll attributes: + - + name: id + type: u32 + - + name: dev-name + type: string + - + name: bus-name + type: string + - + name: pin-direction + type: u8 + - + name: pin-prio + type: u32 - name: pin-state type: u8 - - name: pin-parent-idx + name: pin-id type: u32 - name: pin-rclk-device type: string + - name: pin-frequency-range subset-of: dpll @@ -284,28 +292,6 @@ attribute-sets: - name: pin-frequency-max type: u64 - - - name: device - subset-of: dpll - attributes: - - - name: id - type: u32 - - - name: dev-name - type: string - - - name: bus-name - type: string - - - name: pin-prio - type: u32 - - - name: pin-state - type: u8 - - - name: pin-direction - type: u8 operations: enum-name: dpll_cmd @@ -391,10 +377,10 @@ operations: - id - bus-name - dev-name - - pin-idx + - pin-id reply: &pin-attrs attributes: - - pin-idx + - pin-id - pin-label - pin-type - pin-frequency @@ -402,7 +388,6 @@ operations: - pin-parent - pin-rclk-device - pin-dpll-caps - - device dump: pre: dpll-pin-pre-dumpit @@ -428,12 +413,12 @@ operations: - id - bus-name - dev-name - - pin-idx + - pin-id - pin-frequency - pin-direction - pin-prio - pin-state - - pin-parent-idx + - pin-parent - name: pin-create-ntf doc: Notification about pin appearing diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index e08f5aa4d856..f834c6b1cce8 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -10,6 +10,16 @@ #include +/* Common nested types */ +const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_MAX(NLA_U8, 2), + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, + [DPLL_A_PIN_STATE] = NLA_POLICY_MAX(NLA_U8, 3), + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, + [DPLL_A_PIN_RCLK_DEVICE] = { .type = NLA_NUL_STRING, }, +}; + /* DPLL_CMD_DEVICE_GET - do */ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_BUS_NAME + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, @@ -26,11 +36,11 @@ static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_MODE + 1] = { }; /* DPLL_CMD_PIN_GET - do */ -static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_IDX + 1] = { +static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_PIN_IDX] = { .type = NLA_U32, }, + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, }; /* DPLL_CMD_PIN_GET - dump */ @@ -41,16 +51,16 @@ static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_BUS_NAME + 1] }; /* DPLL_CMD_PIN_SET - do */ -static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_IDX + 1] = { +static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_PIN_IDX] = { .type = NLA_U32, }, + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_MAX(NLA_U8, 2), [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, [DPLL_A_PIN_STATE] = NLA_POLICY_MAX(NLA_U8, 3), - [DPLL_A_PIN_PARENT_IDX] = { .type = NLA_U32, }, + [DPLL_A_PIN_PARENT] = { .type = NLA_NESTED, }, }; /* Ops table for dpll */ @@ -86,7 +96,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { .doit = dpll_nl_pin_get_doit, .post_doit = dpll_pin_post_doit, .policy = dpll_pin_get_do_nl_policy, - .maxattr = DPLL_A_PIN_IDX, + .maxattr = DPLL_A_PIN_ID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -104,7 +114,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { .doit = dpll_nl_pin_set_doit, .post_doit = dpll_pin_post_doit, .policy = dpll_pin_set_nl_policy, - .maxattr = DPLL_A_PIN_PARENT_IDX, + .maxattr = DPLL_A_PIN_PARENT, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, }; diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 57ab2da562ba..9e477a02d3e3 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -11,6 +11,9 @@ #include +/* Common nested types */ +extern const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1]; + int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 29e652777818..61718de7d077 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -143,7 +143,7 @@ enum dpll_a { DPLL_A_TEMP, DPLL_A_CLOCK_ID, DPLL_A_TYPE, - DPLL_A_PIN_IDX, + DPLL_A_PIN_ID, DPLL_A_PIN_LABEL, DPLL_A_PIN_TYPE, DPLL_A_PIN_DIRECTION, @@ -154,10 +154,8 @@ enum dpll_a { DPLL_A_PIN_PRIO, DPLL_A_PIN_STATE, DPLL_A_PIN_PARENT, - DPLL_A_PIN_PARENT_IDX, DPLL_A_PIN_RCLK_DEVICE, DPLL_A_PIN_DPLL_CAPS, - DPLL_A_DEVICE, __DPLL_A_MAX, DPLL_A_MAX = (__DPLL_A_MAX - 1) From c62054c18dc21aebdc1b06206fee7656cc894ae9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 30 May 2023 11:06:55 +0200 Subject: [PATCH 63/93] dpll: core: rename pin-idx to pin-id, remove pin-parent-idx, device dpll device is identified by DPLL_A_ID, now pin is identified with similar name DPLL_A_PIN_ID (consistency). DPLL_PIN_PARENT_IDX is removed as not needed. was used to target a pin parent, instead use a DPLL_A_PIN_PARENT nested attribute which encloses either DPLL_A_ID or DPLL_A_PIN_ID, depending where it is connected. Removed DPLL_A_DEVICE nested attribute as it is replaced by DPLL_A_PIN_PARENT. Fix targeting pin issues, use global pin-id to target correct pin, previously pin was targeted by its driver supplied idx. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 188 ++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 70 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 5c9a5e8541d9..cd4f40ea23ea 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -217,7 +217,7 @@ dpll_msg_add_pin_parents(struct sk_buff *msg, struct dpll_pin *pin, nest = nla_nest_start(msg, DPLL_A_PIN_PARENT); if (!nest) return -EMSGSIZE; - if (nla_put_u32(msg, DPLL_A_PIN_PARENT_IDX, ppin->pin_idx)) { + if (nla_put_u32(msg, DPLL_A_PIN_ID, ppin->id)) { ret = -EMSGSIZE; goto nest_cancel; } @@ -245,7 +245,7 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin, int ret; xa_for_each(&pin->dpll_refs, index, ref) { - attr = nla_nest_start(msg, DPLL_A_DEVICE); + attr = nla_nest_start(msg, DPLL_A_PIN_PARENT); if (!attr) return -EMSGSIZE; ret = dpll_msg_add_dev_handle(msg, ref->dpll); @@ -299,7 +299,7 @@ size_t dpll_msg_pin_handle_size(struct dpll_pin *pin) { // TMP- THE HANDLE IS GOING TO CHANGE TO DRIVERNAME/CLOCKID/PIN_INDEX // LEAVING ORIG HANDLE NOW AS PUT IN THE LAST RFC VERSION - return nla_total_size(4); /* DPLL_A_PIN_IDX */ + return nla_total_size(4); /* DPLL_A_PIN_ID */ } EXPORT_SYMBOL_GPL(dpll_msg_pin_handle_size); @@ -307,7 +307,7 @@ int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin *pin) { // TMP- THE HANDLE IS GOING TO CHANGE TO DRIVERNAME/CLOCKID/PIN_INDEX // LEAVING ORIG HANDLE NOW AS PUT IN THE LAST RFC VERSION - if (nla_put_u32(msg, DPLL_A_PIN_IDX, pin->pin_idx)) + if (nla_put_u32(msg, DPLL_A_PIN_ID, pin->id)) return -EMSGSIZE; return 0; } @@ -408,33 +408,37 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a, } static int -dpll_pin_on_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, - u32 parent_idx, enum dpll_pin_state state, +dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, + enum dpll_pin_state state, struct netlink_ext_ack *extack) { + struct dpll_pin_ref *parent_ref; const struct dpll_pin_ops *ops; - struct dpll_pin_ref *pin_ref, *parent_ref; + struct dpll_pin_ref *dpll_ref; + struct dpll_pin *parent; + unsigned long i; if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop.capabilities)) return -EOPNOTSUPP; - parent_ref = xa_load(&pin->parent_refs, parent_idx); - // dpll_pin_get_by_idx(dpll, parent_idx); - if (!parent_ref) + parent = xa_load(&dpll_pin_xa, parent_idx); + if (!parent) return -EINVAL; - pin_ref = xa_load(&dpll->pin_refs, pin->pin_idx); - if (!pin_ref) + parent_ref = xa_load(&pin->parent_refs, parent->pin_idx); + if (!parent_ref) return -EINVAL; - ops = dpll_pin_ops(pin_ref); - if (!ops->state_on_pin_set) - return -EOPNOTSUPP; - if (ops->state_on_pin_set(pin_ref->pin, - dpll_pin_on_pin_priv(parent_ref->pin, - pin_ref->pin), - parent_ref->pin, - dpll_pin_on_dpll_priv(dpll, parent_ref->pin), - state, extack)) - return -EFAULT; - __dpll_pin_change_ntf(pin_ref->pin); + xa_for_each(&parent->dpll_refs, i, dpll_ref) { + ops = dpll_pin_ops(parent_ref); + if (!ops->state_on_pin_set) + return -EOPNOTSUPP; + if (ops->state_on_pin_set(pin, + dpll_pin_on_pin_priv(parent, pin), + parent, + dpll_pin_on_dpll_priv(dpll_ref->dpll, + parent), + state, extack)) + return -EFAULT; + } + __dpll_pin_change_ntf(pin); return 0; } @@ -465,12 +469,10 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, static int dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, - struct nlattr *prio_attr, struct netlink_ext_ack *extack) + u32 prio, struct netlink_ext_ack *extack) { const struct dpll_pin_ops *ops; struct dpll_pin_ref *ref; - u32 prio = nla_get_u8(prio_attr); - if (!(DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE & pin->prop.capabilities)) return -EOPNOTSUPP; ref = xa_load(&pin->dpll_refs, dpll->device_idx); @@ -513,14 +515,80 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct nlattr *a, } static int -dpll_pin_set_from_nlattr(struct dpll_device *dpll, - struct dpll_pin *pin, struct genl_info *info) +dpll_pin_parent_set(struct dpll_pin *pin, struct nlattr *parent_nest, + struct netlink_ext_ack *extack) +{ + bool state_present = false, prio_present = false; + bool parent_dpll = false, parent_pin = false; + u32 parent_idx, dpll_idx, prio; + enum dpll_pin_state state; + struct dpll_pin_ref *ref; + struct dpll_device *dpll; + struct nlattr *a; + int rem, ret; + + nla_for_each_nested(a, parent_nest, rem) { + switch (nla_type(a)) { + case DPLL_A_ID: + dpll_idx = nla_get_u32(a); + parent_dpll = true; + break; + case DPLL_A_PIN_ID: + parent_idx = nla_get_u32(a); + parent_pin = true; + break; + case DPLL_A_PIN_STATE: + state = nla_get_u8(a); + state_present = true; + break; + case DPLL_A_PIN_PRIO: + prio = nla_get_u32(a); + prio_present = true; + break; + default: + break; + } + } + if (parent_pin && !state_present) { + NL_SET_ERR_MSG(extack, "pin state is missing"); + return -EINVAL; + } + if (parent_dpll && !(state_present || prio_present)) { + NL_SET_ERR_MSG(extack, "both pin state and prio are missing"); + return -EINVAL; + } + if (parent_pin) { + ret = dpll_pin_on_pin_state_set(pin, parent_idx, state, extack); + if (ret) + return ret; + } else if (parent_dpll) { + dpll = xa_load(&dpll_device_xa, dpll_idx); + if (!dpll) + return -EINVAL; + ref = xa_load(&pin->dpll_refs, dpll->device_idx); + if (!ref) + return -EINVAL; + if (state_present) { + + ret = dpll_pin_state_set(dpll, pin, state, extack); + if (ret) + return ret; + } + if (prio_present) { + ret = dpll_pin_prio_set(dpll, pin, prio, extack); + if (ret) + return ret; + } + } + + return 0; +} + +static int +dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info) { - enum dpll_pin_state state = 0; - bool parent_present = false; int rem, ret = -EINVAL; struct nlattr *a; - u32 parent_idx; nla_for_each_attr(a, genlmsg_data(info->genlhdr), genlmsg_len(info->genlhdr), rem) { @@ -535,50 +603,35 @@ dpll_pin_set_from_nlattr(struct dpll_device *dpll, if (ret) return ret; break; - case DPLL_A_PIN_PRIO: - ret = dpll_pin_prio_set(dpll, pin, a, info->extack); + case DPLL_A_PIN_PARENT: + ret = dpll_pin_parent_set(pin, a, info->extack); if (ret) return ret; break; - case DPLL_A_PIN_PARENT_IDX: - parent_present = true; - parent_idx = nla_get_u32(a); - break; - case DPLL_A_PIN_STATE: - state = nla_get_u8(a); + case DPLL_A_PIN_ID: + case DPLL_A_ID: break; default: - break; - } - } - if (state) { - if (!parent_present) { - ret = dpll_pin_state_set(dpll, pin, state, - info->extack); - if (ret) - return ret; - } else { - ret = dpll_pin_on_pin_state_set(dpll, pin, parent_idx, - state, info->extack); - if (ret) - return ret; + NL_SET_ERR_MSG_FMT(info->extack, + "unsupported attribute (%d)", + nla_type(a)); + return -EINVAL; } } - return ret; + return 0; } int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) { - struct dpll_device *dpll = info->user_ptr[0]; - struct dpll_pin *pin = info->user_ptr[1]; + struct dpll_pin *pin = info->user_ptr[0]; - return dpll_pin_set_from_nlattr(dpll, pin, info); + return dpll_pin_set_from_nlattr(pin, info); } int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct dpll_pin *pin = info->user_ptr[1]; + struct dpll_pin *pin = info->user_ptr[0]; struct sk_buff *msg; struct nlattr *hdr; int ret; @@ -771,24 +824,19 @@ int dpll_post_dumpit(struct netlink_callback *cb) int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - int ret = dpll_pre_doit(ops, skb, info); - struct dpll_pin_ref *pin_ref; - struct dpll_device *dpll; + int ret; - if (ret) - return ret; - dpll = info->user_ptr[0]; - if (!info->attrs[DPLL_A_PIN_IDX]) { + mutex_lock(&dpll_xa_lock); + if (!info->attrs[DPLL_A_PIN_ID]) { ret = -EINVAL; goto unlock_dev; } - pin_ref = xa_load(&dpll->pin_refs, - nla_get_u32(info->attrs[DPLL_A_PIN_IDX])); - if (!pin_ref) { + info->user_ptr[0] = xa_load(&dpll_pin_xa, + nla_get_u32(info->attrs[DPLL_A_PIN_ID])); + if (!info->user_ptr[0]) { ret = -ENODEV; goto unlock_dev; } - info->user_ptr[1] = pin_ref->pin; return 0; @@ -800,7 +848,7 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - dpll_post_doit(ops, skb, info); + mutex_unlock(&dpll_xa_lock); } int dpll_pin_pre_dumpit(struct netlink_callback *cb) From 256471a2665f2bf565335d83e8772f3357e92ea3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 30 May 2023 17:35:46 +0200 Subject: [PATCH 64/93] dpll: spec: replace bus-name, dev-name with module-name Remove the bus-name and dev-name attributes, as they are no longer needed. To identify dpll device the one will use: module-name, clock-id and type. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 25 +++---------------------- drivers/dpll/dpll_nl.c | 19 +++++-------------- include/uapi/linux/dpll.h | 3 +-- 3 files changed, 9 insertions(+), 38 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index b062bce8b864..1d0e0297e847 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -179,10 +179,7 @@ attribute-sets: type: u32 value: 1 - - name: dev-name - type: string - - - name: bus-name + name: module-name type: string - name: mode @@ -260,12 +257,6 @@ attribute-sets: - name: id type: u32 - - - name: dev-name - type: string - - - name: bus-name - type: string - name: pin-direction type: u8 @@ -310,13 +301,11 @@ operations: request: attributes: - id - - bus-name - - dev-name + - module-name reply: &dev-attrs attributes: - id - - dev-name - - bus-name + - module-name - mode - mode-supported - lock-status @@ -341,8 +330,6 @@ operations: request: attributes: - id - - bus-name - - dev-name - mode - name: device-create-ntf @@ -375,8 +362,6 @@ operations: request: attributes: - id - - bus-name - - dev-name - pin-id reply: &pin-attrs attributes: @@ -395,8 +380,6 @@ operations: request: attributes: - id - - bus-name - - dev-name reply: *pin-attrs - @@ -411,8 +394,6 @@ operations: request: attributes: - id - - bus-name - - dev-name - pin-id - pin-frequency - pin-direction diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index f834c6b1cce8..703c08f082fe 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -21,40 +21,31 @@ const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1] = }; /* DPLL_CMD_DEVICE_GET - do */ -static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_BUS_NAME + 1] = { +static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_MODULE_NAME + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, - [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, }, }; /* DPLL_CMD_DEVICE_SET - do */ static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_MODE + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, - [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_MODE] = NLA_POLICY_MAX(NLA_U8, 4), }; /* DPLL_CMD_PIN_GET - do */ static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, - [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_PIN_ID] = { .type = NLA_U32, }, }; /* DPLL_CMD_PIN_GET - dump */ -static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_BUS_NAME + 1] = { +static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_ID + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, - [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; /* DPLL_CMD_PIN_SET - do */ static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, - [DPLL_A_BUS_NAME] = { .type = NLA_NUL_STRING, }, - [DPLL_A_DEV_NAME] = { .type = NLA_NUL_STRING, }, [DPLL_A_PIN_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_MAX(NLA_U8, 2), @@ -71,7 +62,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { .doit = dpll_nl_device_get_doit, .post_doit = dpll_post_doit, .policy = dpll_device_get_nl_policy, - .maxattr = DPLL_A_BUS_NAME, + .maxattr = DPLL_A_MODULE_NAME, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -105,7 +96,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { .dumpit = dpll_nl_pin_get_dumpit, .done = dpll_pin_post_dumpit, .policy = dpll_pin_get_dump_nl_policy, - .maxattr = DPLL_A_BUS_NAME, + .maxattr = DPLL_A_ID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 61718de7d077..76f7f43f67c3 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -135,8 +135,7 @@ enum dpll_pin_caps { enum dpll_a { DPLL_A_ID = 1, - DPLL_A_DEV_NAME, - DPLL_A_BUS_NAME, + DPLL_A_MODULE_NAME, DPLL_A_MODE, DPLL_A_MODE_SUPPORTED, DPLL_A_LOCK_STATUS, From ab77d28b0732dd7b8906236e5e7c7730ca36d515 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 30 May 2023 20:01:56 +0200 Subject: [PATCH 65/93] dpll: core: replace bus-name, dev-name with module-name Remove the bus-name and dev-name attributes, as they are no longer needed. To identify dpll device the one will use: module-name, clock-id and type. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 29 ----------------------------- drivers/dpll/dpll_core.h | 1 - drivers/dpll/dpll_netlink.c | 17 ++++++++++------- 3 files changed, 10 insertions(+), 37 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 265d621d5b26..cb3cb7357452 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -41,32 +41,6 @@ struct dpll_device *dpll_device_get_by_id(int id) return NULL; } -/** - * dpll_device_get_by_name - find dpll device by it's id - * @bus_name: bus name of searched dpll - * @dev_name: dev name of searched dpll - * - * Return: - * * dpll_device struct if found - * * NULL otherwise - */ -struct dpll_device * -dpll_device_get_by_name(const char *bus_name, const char *device_name) -{ - struct dpll_device *dpll, *ret = NULL; - unsigned long i; - - xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { - if (!strcmp(dev_bus_name(&dpll->dev), bus_name) && - !strcmp(dev_name(&dpll->dev), device_name)) { - ret = dpll; - break; - } - } - - return ret; -} - static struct dpll_pin_registration * dpll_pin_registration_find(struct dpll_pin_ref *ref, const struct dpll_pin_ops *ops, void *priv) @@ -469,11 +443,8 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, reg->ops = ops; reg->priv = priv; - dpll->dev.bus = owner->bus; dpll->parent = owner; dpll->type = type; - dev_set_name(&dpll->dev, "%s/%llx/%d", module_name(dpll->module), - dpll->clock_id, dpll->device_idx); first_registration = list_empty(&dpll->registration_list); list_add_tail(®->list, &dpll->registration_list); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index e905c1088568..b53324d81d64 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -40,7 +40,6 @@ struct dpll_device { u32 device_idx; u64 clock_id; struct module *module; - struct device dev; struct device *parent; enum dpll_type type; struct xarray pin_refs; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index cd4f40ea23ea..469e82951a77 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -28,10 +28,6 @@ dpll_msg_add_dev_handle(struct sk_buff *msg, struct dpll_device *dpll) { if (nla_put_u32(msg, DPLL_A_ID, dpll->id)) return -EMSGSIZE; - if (nla_put_string(msg, DPLL_A_BUS_NAME, dev_bus_name(&dpll->dev))) - return -EMSGSIZE; - if (nla_put_string(msg, DPLL_A_DEV_NAME, dev_name(&dpll->dev))) - return -EMSGSIZE; return 0; } @@ -279,6 +275,11 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_msg_add_pin_handle(msg, pin); if (ret) return ret; + if (nla_put_string(msg, DPLL_A_MODULE_NAME, pin->module->name)) + return -EMSGSIZE; + if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(pin->clock_id), + &pin->clock_id, 0)) + return -EMSGSIZE; if (nla_put_string(msg, DPLL_A_PIN_LABEL, pin->prop.label)) return -EMSGSIZE; if (nla_put_u8(msg, DPLL_A_PIN_TYPE, pin->prop.type)) @@ -348,6 +349,11 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, ret = dpll_msg_add_dev_handle(msg, dpll); if (ret) return ret; + if (nla_put_string(msg, DPLL_A_MODULE_NAME, dpll->module->name)) + return -EMSGSIZE; + if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), + &dpll->clock_id, 0)) + return -EMSGSIZE; ret = dpll_msg_add_temp(msg, dpll, extack); if (ret && ret != -EOPNOTSUPP) return ret; @@ -361,9 +367,6 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, if (test_bit(mode, &dpll->mode_supported_mask)) if (nla_put_s32(msg, DPLL_A_MODE_SUPPORTED, mode)) return -EMSGSIZE; - if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), - &dpll->clock_id, 0)) - return -EMSGSIZE; if (nla_put_u8(msg, DPLL_A_TYPE, dpll->type)) return -EMSGSIZE; From a91590f5ade01eeaed77795bd7af25c9b1bc22ce Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 13:18:15 +0200 Subject: [PATCH 66/93] dpll: spec: replace pin-label with 3 new attributes Add flexibility in naming pins by replacing pin-label attribute with 3 new attributes: pin-board-label, pin-panel-label and pin-package-label. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 12 ++++++++++-- include/uapi/linux/dpll.h | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 1d0e0297e847..160ea7654bac 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -208,7 +208,13 @@ attribute-sets: name: pin-id type: u32 - - name: pin-label + name: pin-board-label + type: string + - + name: pin-panel-label + type: string + - + name: pin-package-label type: string - name: pin-type @@ -366,7 +372,9 @@ operations: reply: &pin-attrs attributes: - pin-id - - pin-label + - pin-board-label + - pin-panel-label + - pin-package-label - pin-type - pin-frequency - pin-frequency-supported diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 76f7f43f67c3..8eb93344d871 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -143,7 +143,9 @@ enum dpll_a { DPLL_A_CLOCK_ID, DPLL_A_TYPE, DPLL_A_PIN_ID, - DPLL_A_PIN_LABEL, + DPLL_A_PIN_BOARD_LABEL, + DPLL_A_PIN_PANEL_LABEL, + DPLL_A_PIN_PACKAGE_LABEL, DPLL_A_PIN_TYPE, DPLL_A_PIN_DIRECTION, DPLL_A_PIN_FREQUENCY, From 7cd05cd77339a37da1ed7c3dbbf733fb456583d1 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 13:21:20 +0200 Subject: [PATCH 67/93] dpll: core: replace pin-label with 3 new attributes Adapt dpll core part. Add flexibility in naming pins by replacing pin-label attribute with 3 new attributes: pin-board-label, pin-panel-label and pin-package-label. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 20 +++++++++----------- drivers/dpll/dpll_netlink.c | 10 +++++++++- include/linux/dpll.h | 4 +++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index cb3cb7357452..7a4dab86e62f 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -520,15 +520,9 @@ dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, pin->clock_id = clock_id; pin->module = module; refcount_set(&pin->refcount, 1); - if (WARN_ON(!prop->label)) { - ret = -EINVAL; - goto err; - } - pin->prop.label = kstrdup(prop->label, GFP_KERNEL); - if (!pin->prop.label) { - ret = -ENOMEM; - goto err; - } + pin->prop.board_label = kstrdup(prop->board_label, GFP_KERNEL); + pin->prop.panel_label = kstrdup(prop->panel_label, GFP_KERNEL); + pin->prop.package_label = kstrdup(prop->package_label, GFP_KERNEL); if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || prop->type > DPLL_PIN_TYPE_MAX)) { ret = -EINVAL; @@ -556,7 +550,9 @@ dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, err: xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); - kfree(pin->prop.label); + kfree(pin->prop.board_label); + kfree(pin->prop.panel_label); + kfree(pin->prop.package_label); kfree(pin->rclk_dev_name); kfree(pin); return ERR_PTR(ret); @@ -613,7 +609,9 @@ void dpll_pin_put(struct dpll_pin *pin) xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); xa_erase(&dpll_pin_xa, pin->id); - kfree(pin->prop.label); + kfree(pin->prop.board_label); + kfree(pin->prop.panel_label); + kfree(pin->prop.package_label); kfree(pin->prop.freq_supported); kfree(pin->rclk_dev_name); kfree(pin); diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 469e82951a77..d54c43c26f7a 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -280,7 +280,15 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(pin->clock_id), &pin->clock_id, 0)) return -EMSGSIZE; - if (nla_put_string(msg, DPLL_A_PIN_LABEL, pin->prop.label)) + if (pin->prop.board_label && + nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, pin->prop.board_label)) + return -EMSGSIZE; + if (pin->prop.panel_label && + nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, pin->prop.panel_label)) + return -EMSGSIZE; + if (pin->prop.package_label && + nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL, + pin->prop.package_label)) return -EMSGSIZE; if (nla_put_u8(msg, DPLL_A_PIN_TYPE, pin->prop.type)) return -EMSGSIZE; diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 21b448b5883f..3c3e1b194279 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -99,7 +99,9 @@ struct dpll_pin_frequency { DPLL_PIN_FREQUENCY(DPLL_PIN_FREQUENCY_77_5_KHZ) struct dpll_pin_properties { - const char *label; + const char *board_label; + const char *panel_label; + const char *package_label; enum dpll_pin_type type; unsigned long capabilities; u32 freq_supported_num; From 5cd2221a0afa5edbbbb7dc7d0ada1a4b51bb58ba Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 13:22:27 +0200 Subject: [PATCH 68/93] ice: replace pin-label with pin-board-label Adapt ice/dpll part, after change to dpll spec/core, use board_label instead of label field of pin properities. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index bf7712ca3cd5..859c60238170 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1792,7 +1792,7 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf, for (i = 0; i < num_pins; i++) { pins[i].idx = i; - pins[i].prop.label = ice_cgu_get_pin_name(hw, i, input); + pins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input); pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input); if (input) { ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i, @@ -1835,7 +1835,7 @@ static int ice_dpll_init_rclk_pin(struct ice_pf *pf) struct ice_dpll_pin *pin = &pf->dplls.rclk; struct device *dev = ice_pf_to_dev(pf); - pin->prop.label = dev_name(dev); + pin->prop.board_label = dev_name(dev); pin->prop.type = DPLL_PIN_TYPE_SYNCE_ETH_PORT; pin->prop.capabilities |= DPLL_PIN_CAPS_STATE_CAN_CHANGE; pin->pf = pf; From 6cd2307cf94721d45b975c80c71187ec79e6a16c Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 13:31:36 +0200 Subject: [PATCH 69/93] ptp_ocp: replace pin-label with pin-board-label Adapt ptp_ocp/dpll part, after change to dpll spec/core, use board_label instead of label field of pin properities. Signed-off-by: Arkadiusz Kubalewski --- drivers/ptp/ptp_ocp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 63d653329c9c..802e73e70a09 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -2296,7 +2296,7 @@ static void ptp_ocp_sma_fb_init(struct ptp_ocp *bp) { struct dpll_pin_properties prop = { - .label = NULL, + .board_label = NULL, .type = DPLL_PIN_TYPE_EXT, .capabilities = DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE, .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), @@ -2310,7 +2310,8 @@ ptp_ocp_sma_fb_init(struct ptp_ocp *bp) for (i = 0; i < OCP_SMA_NUM; i++) { bp->sma[i].default_fcn = i & 1; bp->sma[i].dpll_prop = prop; - bp->sma[i].dpll_prop.label = bp->ptp_info.pin_config[i].name; + bp->sma[i].dpll_prop.board_label = + bp->ptp_info.pin_config[i].name; } bp->sma[0].mode = SMA_MODE_IN; bp->sma[1].mode = SMA_MODE_IN; @@ -2471,7 +2472,7 @@ static void ptp_ocp_art_sma_init(struct ptp_ocp *bp) { struct dpll_pin_properties prop = { - .label = NULL, + .board_label = NULL, .type = DPLL_PIN_TYPE_EXT, .capabilities = 0, .freq_supported_num = ARRAY_SIZE(ptp_ocp_sma_freq), @@ -2496,7 +2497,8 @@ ptp_ocp_art_sma_init(struct ptp_ocp *bp) for (i = 0; i < OCP_SMA_NUM; i++) { /* If no SMA map, the pin functions and directions are fixed. */ bp->sma[i].dpll_prop = prop; - bp->sma[i].dpll_prop.label = bp->ptp_info.pin_config[i].name; + bp->sma[i].dpll_prop.board_label = + bp->ptp_info.pin_config[i].name; if (!bp->art_sma) { bp->sma[i].fixed_fcn = true; bp->sma[i].fixed_dir = true; From 9da80a7c2e0d4587be9671eeec389f6df351c2ae Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 13:32:46 +0200 Subject: [PATCH 70/93] mlx5: remove pin-label Adapt mlx5/dpll part, after change to dpll spec/core, previously pin-label was required now it is not, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/mellanox/mlx5/core/dpll.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 16ba26f43cfc..41cbdeacc86d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -202,7 +202,6 @@ static const struct dpll_pin_ops mlx5_dpll_pins_ops = { }; static const struct dpll_pin_properties mlx5_dpll_pin_properties = { - .label = "n/a", .type = DPLL_PIN_TYPE_SYNCE_ETH_PORT, .capabilities = DPLL_PIN_CAPS_STATE_CAN_CHANGE, }; From c8d7971ddf732802708764ae4febc6776c8cae60 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 22:08:34 +0200 Subject: [PATCH 71/93] dpll: spec: add device-id-get and pin-id-get commands Allow user to get id of a device or a pin with dpll netlink interface. It requires to provide arguments which result in a single match, otherwise the -EINVAL is returned. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 57 +++++++++++++++++++++++---- drivers/dpll/dpll_nl.c | 43 ++++++++++++++++++-- drivers/dpll/dpll_nl.h | 13 ++++-- include/uapi/linux/dpll.h | 4 +- 4 files changed, 101 insertions(+), 16 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 160ea7654bac..c5dde74b8bab 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -293,11 +293,30 @@ attribute-sets: operations: enum-name: dpll_cmd list: + - + name: device-id-get + doc: | + Get id of dpll device that matches given attributes + value: 1 + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-lock-doit + post: dpll-unlock-doit + request: + attributes: + - module-name + - clock-id + - type + reply: + attributes: + - id + - name: device-get doc: | Get list of DPLL devices (dump) or attributes of a single dpll device - value: 1 attribute-set: dpll flags: [ admin-perm ] @@ -320,8 +339,8 @@ operations: - type dump: - pre: dpll-pre-dumpit - post: dpll-post-dumpit + pre: dpll-lock-dumpit + post: dpll-unlock-dumpit reply: *dev-attrs - @@ -352,12 +371,36 @@ operations: doc: Notification about device configuration being changed notify: device-get mcgrp: monitor + - + name: pin-id-get + doc: | + Get id of a pin that matches given attributes + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-lock-doit + post: dpll-unlock-doit + request: + attributes: + - module-name + - clock-id + - pin-board-label + - pin-panel-label + - pin-package-label + - pin-type + reply: + attributes: + - id + - name: pin-get doc: | Get list of pins and its attributes. - - dump request without any attributes given - list all the pins in the system - - dump request with target dpll - list all the pins registered with a given dpll device + - dump request without any attributes given - list all the pins in the + system + - dump request with target dpll - list all the pins registered with + a given dpll device - do request with target dpll and target pin - single pin attributes attribute-set: dpll flags: [ admin-perm ] @@ -383,8 +426,8 @@ operations: - pin-dpll-caps dump: - pre: dpll-pin-pre-dumpit - post: dpll-pin-post-dumpit + pre: dpll-lock-dumpit + post: dpll-unlock-dumpit request: attributes: - id diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index 703c08f082fe..fd61ca2ed157 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -20,6 +20,13 @@ const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1] = [DPLL_A_PIN_RCLK_DEVICE] = { .type = NLA_NUL_STRING, }, }; +/* DPLL_CMD_DEVICE_ID_GET - do */ +static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + 1] = { + [DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_CLOCK_ID] = { .type = NLA_U64, }, + [DPLL_A_TYPE] = NLA_POLICY_MAX(NLA_U8, 2), +}; + /* DPLL_CMD_DEVICE_GET - do */ static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_MODULE_NAME + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, @@ -32,6 +39,16 @@ static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_MODE + 1] = { [DPLL_A_MODE] = NLA_POLICY_MAX(NLA_U8, 4), }; +/* DPLL_CMD_PIN_ID_GET - do */ +static const struct nla_policy dpll_pin_id_get_nl_policy[DPLL_A_PIN_TYPE + 1] = { + [DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_CLOCK_ID] = { .type = NLA_U64, }, + [DPLL_A_PIN_BOARD_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_PANEL_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_PACKAGE_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_TYPE] = NLA_POLICY_MAX(NLA_U8, 5), +}; + /* DPLL_CMD_PIN_GET - do */ static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, @@ -56,6 +73,15 @@ static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT + 1] = { /* Ops table for dpll */ static const struct genl_split_ops dpll_nl_ops[] = { + { + .cmd = DPLL_CMD_DEVICE_ID_GET, + .pre_doit = dpll_lock_doit, + .doit = dpll_nl_device_id_get_doit, + .post_doit = dpll_unlock_doit, + .policy = dpll_device_id_get_nl_policy, + .maxattr = DPLL_A_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DPLL_CMD_DEVICE_GET, .pre_doit = dpll_pre_doit, @@ -67,9 +93,9 @@ static const struct genl_split_ops dpll_nl_ops[] = { }, { .cmd = DPLL_CMD_DEVICE_GET, - .start = dpll_pre_dumpit, + .start = dpll_lock_dumpit, .dumpit = dpll_nl_device_get_dumpit, - .done = dpll_post_dumpit, + .done = dpll_unlock_dumpit, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { @@ -81,6 +107,15 @@ static const struct genl_split_ops dpll_nl_ops[] = { .maxattr = DPLL_A_MODE, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, + { + .cmd = DPLL_CMD_PIN_ID_GET, + .pre_doit = dpll_lock_doit, + .doit = dpll_nl_pin_id_get_doit, + .post_doit = dpll_unlock_doit, + .policy = dpll_pin_id_get_nl_policy, + .maxattr = DPLL_A_PIN_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DPLL_CMD_PIN_GET, .pre_doit = dpll_pin_pre_doit, @@ -92,9 +127,9 @@ static const struct genl_split_ops dpll_nl_ops[] = { }, { .cmd = DPLL_CMD_PIN_GET, - .start = dpll_pin_pre_dumpit, + .start = dpll_lock_dumpit, .dumpit = dpll_nl_pin_get_dumpit, - .done = dpll_pin_post_dumpit, + .done = dpll_unlock_dumpit, .policy = dpll_pin_get_dump_nl_policy, .maxattr = DPLL_A_ID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 9e477a02d3e3..806efeff4c1d 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -14,24 +14,29 @@ /* Common nested types */ extern const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1]; +int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); void +dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); -int dpll_pre_dumpit(struct netlink_callback *cb); -int dpll_pin_pre_dumpit(struct netlink_callback *cb); -int dpll_post_dumpit(struct netlink_callback *cb); -int dpll_pin_post_dumpit(struct netlink_callback *cb); +int dpll_lock_dumpit(struct netlink_callback *cb); +int dpll_unlock_dumpit(struct netlink_callback *cb); +int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info); int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info); int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info); int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info); int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info); diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 8eb93344d871..96c34e1bfb18 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -163,11 +163,13 @@ enum dpll_a { }; enum dpll_cmd { - DPLL_CMD_DEVICE_GET = 1, + DPLL_CMD_DEVICE_ID_GET = 1, + DPLL_CMD_DEVICE_GET, DPLL_CMD_DEVICE_SET, DPLL_CMD_DEVICE_CREATE_NTF, DPLL_CMD_DEVICE_DELETE_NTF, DPLL_CMD_DEVICE_CHANGE_NTF, + DPLL_CMD_PIN_ID_GET, DPLL_CMD_PIN_GET, DPLL_CMD_PIN_SET, DPLL_CMD_PIN_CREATE_NTF, From 561a92faa5383d85cc8c33e1a46214b307ffb3ec Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Thu, 1 Jun 2023 23:31:55 +0200 Subject: [PATCH 72/93] dpll: core: add device-id-get and pin-id-get commands Allow user to get id of a device or a pin with dpll netlink interface. It requires to provide arguments which result in a single match, otherwise the -EINVAL is returned. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 246 +++++++++++++++++++++++++++++++++--- 1 file changed, 228 insertions(+), 18 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index d54c43c26f7a..2ed3d1cf83f9 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -633,11 +633,120 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info) return 0; } -int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) +static struct dpll_pin * +dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, + enum dpll_pin_type type, struct nlattr *board_label, + struct nlattr *panel_label, struct nlattr *package_label) { - struct dpll_pin *pin = info->user_ptr[0]; + bool board_match, panel_match, package_match; + struct dpll_pin *pin_match = NULL, *pin; + bool cid_match, mod_match, type_match; + unsigned long i; - return dpll_pin_set_from_nlattr(pin, info); + xa_for_each(&dpll_pin_xa, i, pin) { + if (xa_empty(&pin->dpll_refs)) + continue; + cid_match = clock_id ? pin->clock_id == clock_id : true; + mod_match = mod_name_attr ? + !nla_strcmp(mod_name_attr, pin->module->name) : true; + type_match = type ? pin->prop.type == type : true; + board_match = board_label && pin->prop.board_label ? + !nla_strcmp(board_label, pin->prop.board_label) : true; + panel_match = panel_label && pin->prop.panel_label ? + !nla_strcmp(panel_label, pin->prop.panel_label) : true; + package_match = package_label && pin->prop.package_label ? + !nla_strcmp(package_label, + pin->prop.package_label) : true; + if (cid_match && mod_match && type_match && board_match && + panel_match && package_match) { + if (pin_match) + return NULL; + pin_match = pin; + }; + } + + return pin_match; +} + +static int +dpll_pin_find_from_nlattr(struct genl_info *info, struct sk_buff *skb) +{ + struct nlattr *attr, *mod_name_attr = NULL, *board_label_attr = NULL, + *panel_label_attr = NULL, *package_label_attr = NULL; + struct dpll_pin *pin = NULL; + enum dpll_pin_type type = 0; + u64 clock_id = 0; + int rem = 0; + + nla_for_each_attr(attr, genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), rem) { + switch (nla_type(attr)) { + case DPLL_A_CLOCK_ID: + if (clock_id) + return -EINVAL; + clock_id = nla_get_u64(attr); + break; + case DPLL_A_MODULE_NAME: + if (mod_name_attr) + return -EINVAL; + mod_name_attr = attr; + break; + case DPLL_A_PIN_TYPE: + if (type) + return -EINVAL; + type = nla_get_u8(attr); + break; + case DPLL_A_PIN_BOARD_LABEL: + if (board_label_attr) + return -EINVAL; + board_label_attr = attr; + break; + case DPLL_A_PIN_PANEL_LABEL: + if (panel_label_attr) + return -EINVAL; + panel_label_attr = attr; + break; + case DPLL_A_PIN_PACKAGE_LABEL: + if (package_label_attr) + return -EINVAL; + package_label_attr = attr; + break; + default: + break; + } + } + if (!(clock_id || mod_name_attr || board_label_attr || + panel_label_attr || package_label_attr)) + return -EINVAL; + pin = dpll_pin_find(clock_id, mod_name_attr, type, board_label_attr, + panel_label_attr, package_label_attr); + if (!pin) + return -EINVAL; + return dpll_msg_add_pin_handle(skb, pin); +} + +int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct nlattr *hdr; + int ret; + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, + DPLL_CMD_PIN_ID_GET); + if (!hdr) + return -EMSGSIZE; + + ret = dpll_pin_find_from_nlattr(info, msg); + if (ret) { + nlmsg_free(msg); + return ret; + } + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); } int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info) @@ -699,6 +808,77 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) return ret; } +int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_pin *pin = info->user_ptr[0]; + + return dpll_pin_set_from_nlattr(pin, info); +} + +static struct dpll_device * +dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr, + enum dpll_type type) +{ + struct dpll_device *dpll_match = NULL, *dpll; + bool cid_match, mod_match, type_match; + unsigned long i; + + xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { + cid_match = clock_id ? dpll->clock_id == clock_id : true; + mod_match = mod_name_attr ? + !nla_strcmp(mod_name_attr, dpll->module->name) : true; + type_match = type ? dpll->type == type : true; + if (cid_match && mod_match && type_match) { + if (dpll_match) + return NULL; + dpll_match = dpll; + } + } + + return dpll_match; +} + +static int +dpll_device_find_from_nlattr(struct genl_info *info, struct sk_buff *skb) +{ + struct nlattr *attr, *mod_name_attr = NULL; + struct dpll_device *dpll = NULL; + enum dpll_type type = 0; + u64 clock_id = 0; + int rem = 0; + + nla_for_each_attr(attr, genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), rem) { + switch (nla_type(attr)) { + case DPLL_A_CLOCK_ID: + if (clock_id) + return -EINVAL; + clock_id = nla_get_u64(attr); + break; + case DPLL_A_MODULE_NAME: + if (mod_name_attr) + return -EINVAL; + mod_name_attr = attr; + break; + case DPLL_A_TYPE: + if (type) + return -EINVAL; + type = nla_get_u8(attr); + break; + default: + break; + } + } + + if (!clock_id && !mod_name_attr && !type) + return -EINVAL; + dpll = dpll_device_find(clock_id, mod_name_attr, type); + if (!dpll) + return -EINVAL; + + return dpll_msg_add_dev_handle(skb, dpll); +} + static int dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info) { @@ -726,11 +906,28 @@ dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info) return ret; } -int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) +int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) { - struct dpll_device *dpll = info->user_ptr[0]; + struct sk_buff *msg; + struct nlattr *hdr; + int ret; - return dpll_set_from_nlattr(dpll, info); + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + hdr = genlmsg_put_reply(msg, info, &dpll_nl_family, 0, + DPLL_CMD_DEVICE_ID_GET); + if (!hdr) + return -EMSGSIZE; + + ret = dpll_device_find_from_nlattr(info, msg); + if (ret) { + nlmsg_free(msg); + return ret; + } + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); } int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) @@ -758,6 +955,13 @@ int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_device *dpll = info->user_ptr[0]; + + return dpll_set_from_nlattr(dpll, info); +} + int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { struct dpll_dump_ctx *ctx = dpll_dump_context(cb); @@ -818,14 +1022,30 @@ void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, mutex_unlock(&dpll_xa_lock); } -int dpll_pre_dumpit(struct netlink_callback *cb) +int +dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) { mutex_lock(&dpll_xa_lock); return 0; } -int dpll_post_dumpit(struct netlink_callback *cb) +void +dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + mutex_unlock(&dpll_xa_lock); +} + +int dpll_lock_dumpit(struct netlink_callback *cb) +{ + mutex_lock(&dpll_xa_lock); + + return 0; +} + +int dpll_unlock_dumpit(struct netlink_callback *cb) { mutex_unlock(&dpll_xa_lock); @@ -862,16 +1082,6 @@ void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, mutex_unlock(&dpll_xa_lock); } -int dpll_pin_pre_dumpit(struct netlink_callback *cb) -{ - return dpll_pre_dumpit(cb); -} - -int dpll_pin_post_dumpit(struct netlink_callback *cb) -{ - return dpll_post_dumpit(cb); -} - static int dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll) { From 32f3aeeed03f1e443a27659a86bac8426f4b9184 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Mon, 5 Jun 2023 22:41:52 +0200 Subject: [PATCH 73/93] dpll: core: rename dpll_xa_lock to dpll_lock Rename mutex to better reflect the intentions, the lock is to serialize access to dpll subsytem internal data structures and prevent concurrent access of netlink callbacks and dpll core functions. One global lock for any access to the dpll subsystem. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 50 ++++++++++++++++++------------------- drivers/dpll/dpll_core.h | 2 +- drivers/dpll/dpll_netlink.c | 28 ++++++++++----------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 7a4dab86e62f..070691f61808 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -15,7 +15,7 @@ #include "dpll_core.h" -DEFINE_MUTEX(dpll_xa_lock); +DEFINE_MUTEX(dpll_lock); DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); @@ -347,7 +347,7 @@ dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) struct dpll_device *dpll, *ret = NULL; unsigned long index; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); xa_for_each(&dpll_device_xa, index, dpll) { if (dpll->clock_id == clock_id && dpll->device_idx == device_idx && @@ -359,7 +359,7 @@ dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) } if (!ret) ret = dpll_device_alloc(clock_id, device_idx, module); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return ret; } @@ -376,7 +376,7 @@ void dpll_device_put(struct dpll_device *dpll) { if (!dpll) return; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); if (refcount_dec_and_test(&dpll->refcount)) { ASSERT_DPLL_NOT_REGISTERED(dpll); WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); @@ -385,7 +385,7 @@ void dpll_device_put(struct dpll_device *dpll) WARN_ON(!list_empty(&dpll->registration_list)); kfree(dpll); } - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } EXPORT_SYMBOL_GPL(dpll_device_put); @@ -428,16 +428,16 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX)) return -EINVAL; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); reg = dpll_device_registration_find(dpll, ops, priv); if (reg) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return -EEXIST; } reg = kzalloc(sizeof(*reg), GFP_KERNEL); if (!reg) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return -EEXIST; } reg->ops = ops; @@ -449,12 +449,12 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, first_registration = list_empty(&dpll->registration_list); list_add_tail(®->list, &dpll->registration_list); if (!first_registration) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return 0; } xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); dpll_device_create_ntf(dpll); return 0; @@ -475,23 +475,23 @@ void dpll_device_unregister(struct dpll_device *dpll, { struct dpll_device_registration *reg; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); ASSERT_DPLL_REGISTERED(dpll); dpll_device_delete_ntf(dpll); reg = dpll_device_registration_find(dpll, ops, priv); if (WARN_ON(!reg)) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return; } list_del(®->list); kfree(reg); if (!list_empty(&dpll->registration_list)) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return; } xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } EXPORT_SYMBOL_GPL(dpll_device_unregister); @@ -673,9 +673,9 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, const char *rclk_name = rclk_device ? dev_name(rclk_device) : NULL; int ret; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); ret = __dpll_pin_register(dpll, pin, ops, priv, rclk_name); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return ret; } @@ -704,9 +704,9 @@ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, if (WARN_ON(xa_empty(&dpll->pin_refs))) return; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); __dpll_pin_unregister(dpll, pin, ops, priv); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } EXPORT_SYMBOL_GPL(dpll_pin_unregister); @@ -742,11 +742,11 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, goto unlock; refcount_inc(&pin->refcount); xa_for_each(&parent->dpll_refs, i, ref) { - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); ret = __dpll_pin_register(ref->dpll, pin, ops, priv, rclk_device ? dev_name(rclk_device) : NULL); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); if (ret) { stop = i; goto dpll_unregister; @@ -759,9 +759,9 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, dpll_unregister: xa_for_each(&parent->dpll_refs, i, ref) { if (i < stop) { - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); __dpll_pin_unregister(ref->dpll, pin, ops, priv); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } } refcount_dec(&pin->refcount); @@ -786,14 +786,14 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, struct dpll_pin_ref *ref; unsigned long i; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); dpll_pin_delete_ntf(pin); dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv); refcount_dec(&pin->refcount); xa_for_each(&pin->dpll_refs, i, ref) { __dpll_pin_unregister(ref->dpll, pin, ops, priv); } - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister); @@ -900,7 +900,7 @@ static int __init dpll_init(void) return 0; error: - mutex_destroy(&dpll_xa_lock); + mutex_destroy(&dpll_lock); return ret; } subsys_initcall(dpll_init); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index b53324d81d64..27d6ad45b451 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -108,5 +108,5 @@ const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref); struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs); extern struct xarray dpll_device_xa; extern struct xarray dpll_pin_xa; -extern struct mutex dpll_xa_lock; +extern struct mutex dpll_lock; #endif diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 2ed3d1cf83f9..e002d2d99e12 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -1003,7 +1003,7 @@ int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, if (!info->attrs[DPLL_A_ID]) return -EINVAL; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); id = nla_get_u32(info->attrs[DPLL_A_ID]); dpll_id = dpll_device_get_by_id(id); @@ -1012,21 +1012,21 @@ int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, info->user_ptr[0] = dpll_id; return 0; unlock: - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return -ENODEV; } void dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); return 0; } @@ -1035,19 +1035,19 @@ void dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } int dpll_lock_dumpit(struct netlink_callback *cb) { - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); return 0; } int dpll_unlock_dumpit(struct netlink_callback *cb) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return 0; } @@ -1057,7 +1057,7 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, { int ret; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); if (!info->attrs[DPLL_A_PIN_ID]) { ret = -EINVAL; goto unlock_dev; @@ -1072,14 +1072,14 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, return 0; unlock_dev: - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return ret; } void dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); } static int @@ -1131,9 +1131,9 @@ int dpll_device_change_ntf(struct dpll_device *dpll) if (WARN_ON(!dpll)) return ret; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); ret = dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return ret; } @@ -1196,9 +1196,9 @@ int dpll_pin_change_ntf(struct dpll_pin *pin) if (WARN_ON(!pin)) return ret; - mutex_lock(&dpll_xa_lock); + mutex_lock(&dpll_lock); ret = __dpll_pin_change_ntf(pin); - mutex_unlock(&dpll_xa_lock); + mutex_unlock(&dpll_lock); return ret; } From 7eb4323ee51de9824536e6a4435d4739f0d55fe9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 00:57:34 +0200 Subject: [PATCH 74/93] dpll: core: improve doxygen in dpll_core.c Improve doxygen description of functions and their return values. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 109 ++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 070691f61808..321428011431 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -29,6 +29,7 @@ DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); * dpll_device_get_by_id - find dpll device by it's id * @id: id of searched dpll * + * Context: shall be called under a lock (dpll_lock) * Return: * * dpll_device struct if found * * NULL otherwise @@ -41,6 +42,19 @@ struct dpll_device *dpll_device_get_by_id(int id) return NULL; } +/** + * dpll_pin_registration_find - find a pin registration record + * @ref: reference between dpll and pin + * @ops: searched pin ops pointer + * @priv: searched pin priv pointer + * + * Search dpll's registered pins for given ops and priv data. + * + * Context: shall be called under a lock (dpll_lock) + * Return: + * * NULL - if pin was not found + * * pointer to `struct dpll_pin_registration` if found + */ static struct dpll_pin_registration * dpll_pin_registration_find(struct dpll_pin_ref *ref, const struct dpll_pin_ops *ops, void *priv) @@ -64,6 +78,7 @@ dpll_pin_registration_find(struct dpll_pin_ref *ref, * Allocate and create reference of a pin and enlist a registration * structure storing ops and priv pointers of a caller registant. * + * Context: shall be called under a lock (dpll_lock) * Return: * * 0 on success * * -ENOMEM on failed allocation @@ -127,6 +142,7 @@ dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, * Decrement refcount of existing pin reference on given xarray. * If all registrations are lifted delete the reference and free its memory. * + * Context: shall be called under a lock (dpll_lock) * Return: * * 0 on success * * -EINVAL if reference to a pin was not found @@ -167,6 +183,7 @@ static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin, * Allocate and create reference of a dpll-pin ops or increase refcount * on existing dpll reference on given xarray. * + * Context: shall be called under a lock (dpll_lock) * Return: * * 0 on success * * -ENOMEM on failed allocation @@ -229,6 +246,8 @@ dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, * * Decrement refcount of existing dpll reference on given xarray. * If all references are dropped, delete the reference and free its memory. + * + * Context: shall be called under a lock (dpll_lock) */ static void dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, @@ -262,6 +281,7 @@ dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, * * Search for dpll-pin ops reference struct of a given dpll on given xarray. * + * Context: shall be called under a lock (dpll_lock) * Return: * * pin reference struct pointer on success * * NULL - reference to a pin was not found @@ -280,6 +300,13 @@ dpll_xa_ref_dpll_find(struct xarray *xa_refs, const struct dpll_device *dpll) return NULL; } +/** + * dpll_xa_ref_dpll_first - find first record of given xarray + * @xa_refs: xarray + * + * Context: shall be called under a lock (dpll_lock) + * Return: first element on given xaaray + */ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs) { struct dpll_pin_ref *ref; @@ -299,9 +326,11 @@ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs) * Allocates memory and initialize dpll device, hold its reference on global * xarray. * + * Context: shall be called under a lock (dpll_lock) * Return: - * * dpll_device struct pointer if succeeded - * * ERR_PTR(X) - failed allocation + * * valid dpll_device struct pointer if succeeded + * * ERR_PTR(-ENOMEM) - failed memory allocation + * * ERR_PTR(X) - failed allocation on dpll's xa */ static struct dpll_device * dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) @@ -337,9 +366,11 @@ dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) * Get existing object of a dpll device, unique for given arguments. * Create new if doesn't exist yet. * + * Context: Acquires a lock (dpll_lock) * Return: * * valid dpll_device struct pointer if succeeded - * * ERR_PTR of an error + * * ERR_PTR(-ENOMEM) - failed memory allocation + * * ERR_PTR(X) - failed allocation on dpll's xa */ struct dpll_device * dpll_device_get(u64 clock_id, u32 device_idx, struct module *module) @@ -369,6 +400,7 @@ EXPORT_SYMBOL_GPL(dpll_device_get); * dpll_device_put - decrease the refcount and free memory if possible * @dpll: dpll_device struct pointer * + * Context: Acquires a lock (dpll_lock) * Drop reference for a dpll device, if all references are gone, delete * dpll device object. */ @@ -412,9 +444,11 @@ dpll_device_registration_find(struct dpll_device *dpll, * * Make dpll device available for user space. * + * Context: Acquires a lock (dpll_lock) * Return: * * 0 on success - * * -EINVAL on failure + * * -EINVAL on failure due to wrong arguments provided + * * -EEXIST if device was already registered */ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, const struct dpll_device_ops *ops, void *priv, @@ -462,13 +496,14 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, EXPORT_SYMBOL_GPL(dpll_device_register); /** - * dpll_device_unregister - deregister dpll device + * dpll_device_unregister - unregister dpll device * @dpll: registered dpll pointer * @ops: ops for a dpll device * @priv: pointer to private information of owner * - * Deregister device, make it unavailable for userspace. + * Unregister device, make it unavailable for userspace. * Note: It does not free the memory + * Context: Acquires a lock (dpll_lock) */ void dpll_device_unregister(struct dpll_device *dpll, const struct dpll_device_ops *ops, void *priv) @@ -502,9 +537,11 @@ EXPORT_SYMBOL_GPL(dpll_device_unregister); * @module: reference to registering module * @prop: dpll pin properties * + * Context: shall be called under a lock (dpll_lock) * Return: - * valid allocated dpll_pin struct pointer if succeeded - * ERR_PTR of an error + * * valid allocated dpll_pin struct pointer if succeeded + * * ERR_PTR(-ENOMEM) - failed memory allocation + * * ERR_PTR(-EINVAL) - wrong pin type property value */ static struct dpll_pin * dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, @@ -568,6 +605,7 @@ dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, * Get existing object of a pin (unique for given arguments) or create new * if doesn't exist yet. * + * Context: shall be called under a lock (dpll_lock) * Return: * * valid allocated dpll_pin struct pointer if succeeded * * ERR_PTR of an error @@ -600,6 +638,8 @@ EXPORT_SYMBOL_GPL(dpll_pin_get); * @dpll: dpll_device struct pointer * * Drop reference for a pin, if all references are gone, delete pin object. + * + * Context: shall be called under a lock (dpll_lock) */ void dpll_pin_put(struct dpll_pin *pin) { @@ -660,9 +700,10 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, * @priv: pointer to private information of owner * @rclk_device: pointer to recovered clock device * + * Context: Acquires a lock (dpll_lock) * Return: * * 0 on success - * * -EINVAL - missing dpll or pin + * * -EINVAL - missing pin ops * * -ENOMEM - failed to allocate memory */ int @@ -690,13 +731,14 @@ __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, } /** - * dpll_pin_unregister - deregister dpll pin from dpll device + * dpll_pin_unregister - unregister dpll pin from dpll device * @dpll: registered dpll pointer * @pin: pointer to a pin * @ops: ops for a dpll pin * @priv: pointer to private information of owner * * Note: It does not free the memory + * Context: Acquires a lock (dpll_lock) */ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv) @@ -721,6 +763,7 @@ EXPORT_SYMBOL_GPL(dpll_pin_unregister); * Register a pin with a parent pin, create references between them and * between newly registered pin and dplls connected with a parent pin. * + * Context: Acquires a lock (dpll_lock) * Return: * * 0 on success * * -EINVAL missing pin or parent @@ -772,12 +815,13 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register); /** - * dpll_pin_on_pin_unregister - deregister dpll pin from a parent pin + * dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin * @parent: pointer to a parent pin * @pin: pointer to a pin * @ops: ops for a dpll pin * @priv: pointer to private information of owner * + * Context: Acquires a lock (dpll_lock) * Note: It does not free the memory */ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, @@ -797,6 +841,14 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, } EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister); + +/** + * dpll_device_registration_first - get first registration of dpll device + * @dpll: pointer to a dpll + * + * Context: shall be called under a lock (dpll_lock) + * Return: pointer to the first registration of a dpll + */ static struct dpll_device_registration * dpll_device_registration_first(struct dpll_device *dpll) { @@ -810,9 +862,10 @@ dpll_device_registration_first(struct dpll_device *dpll) /** * dpll_priv - get the dpll device private owner data - * @dpll: registered dpll pointer + * @dpll: registered dpll pointer * - * Return: pointer to the data + * Context: shall be called under a lock (dpll_lock) + * Return: pointer to the first registration priv data */ void *dpll_priv(const struct dpll_device *dpll) { @@ -822,6 +875,13 @@ void *dpll_priv(const struct dpll_device *dpll) return reg->priv; } +/** + * dpll_device_ops - get the dpll device ops pointer + * @dpll: registered dpll pointer + * + * Context: shall be called under a lock (dpll_lock) + * Return: pointer to the first registration ops of the dpll + */ const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll) { struct dpll_device_registration *reg; @@ -830,6 +890,13 @@ const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll) return reg->ops; } +/** + * dpll_pin_registration_first - get first registration of dpll pin ref + * @ref: pointer to a pin ref struct + * + * Context: shall be called under a lock (dpll_lock) + * Return: pointer to the first registration of a dpll_pin_ref + */ static struct dpll_pin_registration * dpll_pin_registration_first(struct dpll_pin_ref *ref) { @@ -846,6 +913,7 @@ dpll_pin_registration_first(struct dpll_pin_ref *ref) * @dpll: registered dpll pointer * @pin: pointer to a pin * + * Context: shall be called under a lock (dpll_lock) * Return: pointer to the data */ void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, @@ -866,6 +934,7 @@ void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, * @parent: pointer to a parent pin * @pin: pointer to a pin * + * Context: shall be called under a lock (dpll_lock) * Return: pointer to the data */ void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, @@ -881,6 +950,13 @@ void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, return reg->priv; } +/** + * dpll_pin_ops - get the pin ops pointer + * @ref: dpll pin ref + * + * Context: shall be called under a lock (dpll_lock) + * Return: pointer to the first ops registered with the pin + */ const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref) { struct dpll_pin_registration *reg; @@ -889,6 +965,13 @@ const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref) return reg->ops; } +/** + * dpll_init - initialize dpll subsystem + * + * Return: + * 0 - success + * negative - netlink init error + */ static int __init dpll_init(void) { int ret; From 87a0f523ff2ed7613775718459745f4f1ede1da2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 10:25:46 +0200 Subject: [PATCH 75/93] dpll: core: remove parent and dev fields from dpll_device Remove unused struct fields, adapt dpll_device_register. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 9 ++------- drivers/dpll/dpll_core.h | 11 ++++------- include/linux/dpll.h | 6 ++---- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 321428011431..4df212acde7a 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -440,7 +440,6 @@ dpll_device_registration_find(struct dpll_device *dpll, * @type: type of a dpll * @ops: ops for a dpll device * @priv: pointer to private information of owner - * @owner: pointer to owner device * * Make dpll device available for user space. * @@ -451,13 +450,12 @@ dpll_device_registration_find(struct dpll_device *dpll, * * -EEXIST if device was already registered */ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, - const struct dpll_device_ops *ops, void *priv, - struct device *owner) + const struct dpll_device_ops *ops, void *priv) { struct dpll_device_registration *reg; bool first_registration = false; - if (WARN_ON(!ops || !owner)) + if (WARN_ON(!ops)) return -EINVAL; if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX)) return -EINVAL; @@ -476,10 +474,7 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, } reg->ops = ops; reg->priv = priv; - - dpll->parent = owner; dpll->type = type; - first_registration = list_empty(&dpll->registration_list); list_add_tail(®->list, &dpll->registration_list); if (!first_registration) { diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 27d6ad45b451..874999e1bfb7 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -21,12 +21,10 @@ struct dpll_device_registration { /** * struct dpll_device - structure for a DPLL device - * @id: unique id number for each device - * @dev_driver_id: id given by dev driver + * @id: unique id number for each device given by kernel + * @device_idx: id given by dev driver * @clock_id: unique identifier (clock_id) of a dpll * @module: module of creator - * @dev: struct device for this dpll device - * @parent: parent device * @ops: operations this &dpll_device supports * @lock: mutex to serialize operations * @type: type of a dpll @@ -40,7 +38,6 @@ struct dpll_device { u32 device_idx; u64 clock_id; struct module *module; - struct device *parent; enum dpll_type type; struct xarray pin_refs; unsigned long mode_supported_mask; @@ -50,8 +47,8 @@ struct dpll_device { /** * struct dpll_pin - structure for a dpll pin - * @idx: unique idx given by alloc on global pin's XA - * @dev_driver_id: id given by dev driver + * @id: unique id number for pin given by kernel + * @pin_idx: index of a pin given by dev driver * @clock_id: clock_id of creator * @module: module of creator * @dpll_refs: hold referencees to dplls that pin is registered with diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 3c3e1b194279..388b97c01a85 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -156,12 +156,10 @@ void dpll_device_put(struct dpll_device *dpll); * @type: type of dpll * @ops: callbacks * @priv: private data of registerer - * @owner: device struct of the owner * */ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, - const struct dpll_device_ops *ops, void *priv, - struct device *owner); + const struct dpll_device_ops *ops, void *priv); /** * dpll_device_unregister - deregister registered dpll @@ -178,7 +176,7 @@ void dpll_device_unregister(struct dpll_device *dpll, /** * dpll_pin_get - get reference or create new pin object * @clock_id: a system unique number of a device - * @@dev_driver_id: index of dpll device on parent device + * @dev_driver_id: index of dpll device on parent device * @module: register module * @pin_prop: constant properities of a pin * From 374e2d03a09ed72f5dc364b53a7278ffd8e9a208 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 10:29:01 +0200 Subject: [PATCH 76/93] ice: dpll remove parent and dev fields from dpll_device Adapt dpll_device_register `owner` argument was removed. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 859c60238170..9a0c20071766 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1465,7 +1465,6 @@ static int ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, enum dpll_type type) { - struct device *dev = ice_pf_to_dev(pf); u64 clock_id = pf->dplls.clock_id; int ret; @@ -1478,8 +1477,7 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu, } d->pf = pf; if (cgu) { - ret = dpll_device_register(d->dpll, type, &ice_dpll_ops, - d, dev); + ret = dpll_device_register(d->dpll, type, &ice_dpll_ops, d); if (ret) { dpll_device_put(d->dpll); return ret; From 0844a90feef0d7005d966b6937c6b1553dcd8a8b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 10:30:16 +0200 Subject: [PATCH 77/93] ptp_ocp: dpll remove parent and dev fields from dpll_device Adapt dpll_device_register `owner` argument was removed. Signed-off-by: Arkadiusz Kubalewski --- drivers/ptp/ptp_ocp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 802e73e70a09..440d1d8803bd 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -4419,7 +4419,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out; } - err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp, &pdev->dev); + err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp); if (err) goto out; From f8e6e586a6acd0a345ffcc88271662daf8f6a59a Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 10:30:50 +0200 Subject: [PATCH 78/93] mlx5: dpll remove parent and dev fields from dpll_device Adapt dpll_device_register `owner` argument was removed. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/mellanox/mlx5/core/dpll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 41cbdeacc86d..fa261e1854a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -330,7 +330,7 @@ static int mlx5_dpll_probe(struct auxiliary_device *adev, } err = dpll_device_register(mdpll->dpll, DPLL_TYPE_EEC, - &mlx5_dpll_device_ops, mdpll, &adev->dev); + &mlx5_dpll_device_ops, mdpll); if (err) goto err_put_dpll_device; From 71fb5c53b6dee05a73151dc3c1642463b4dfcba3 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 10:34:10 +0200 Subject: [PATCH 79/93] dpll: core: use u32 for pin_idx in dpll_pin_alloc The argument shall be u32 as in struct or in caller dpll_pin_get. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 4df212acde7a..b973b4d15af5 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -539,7 +539,7 @@ EXPORT_SYMBOL_GPL(dpll_device_unregister); * * ERR_PTR(-EINVAL) - wrong pin type property value */ static struct dpll_pin * -dpll_pin_alloc(u64 clock_id, u8 pin_idx, struct module *module, +dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, const struct dpll_pin_properties *prop) { struct dpll_pin *pin; From 1e6ee38e16349c908761f48615fbc7ca620c0191 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 11:59:42 +0200 Subject: [PATCH 80/93] dpll: core: use driver provided pin properties Instead of copying data from driver provided pin property use provided pointer during pin lifetime. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 31 +++------------------- drivers/dpll/dpll_core.h | 4 +-- drivers/dpll/dpll_netlink.c | 53 ++++++++++++++++++++----------------- include/linux/dpll.h | 7 ++--- 4 files changed, 38 insertions(+), 57 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index b973b4d15af5..8685c2eb0103 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -543,7 +543,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, const struct dpll_pin_properties *prop) { struct dpll_pin *pin; - int ret, fs_size; + int ret; pin = kzalloc(sizeof(*pin), GFP_KERNEL); if (!pin) @@ -551,28 +551,13 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, pin->pin_idx = pin_idx; pin->clock_id = clock_id; pin->module = module; - refcount_set(&pin->refcount, 1); - pin->prop.board_label = kstrdup(prop->board_label, GFP_KERNEL); - pin->prop.panel_label = kstrdup(prop->panel_label, GFP_KERNEL); - pin->prop.package_label = kstrdup(prop->package_label, GFP_KERNEL); if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || prop->type > DPLL_PIN_TYPE_MAX)) { ret = -EINVAL; goto err; } - pin->prop.type = prop->type; - pin->prop.capabilities = prop->capabilities; - if (prop->freq_supported_num) { - fs_size = sizeof(*pin->prop.freq_supported) * - prop->freq_supported_num; - pin->prop.freq_supported = kzalloc(fs_size, GFP_KERNEL); - if (!pin->prop.freq_supported) { - ret = -ENOMEM; - goto err; - } - memcpy(pin->prop.freq_supported, prop->freq_supported, fs_size); - pin->prop.freq_supported_num = prop->freq_supported_num; - } + pin->prop = prop; + refcount_set(&pin->refcount, 1); xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); ret = xa_alloc(&dpll_pin_xa, &pin->id, pin, xa_limit_16b, GFP_KERNEL); @@ -582,10 +567,6 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, err: xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); - kfree(pin->prop.board_label); - kfree(pin->prop.panel_label); - kfree(pin->prop.package_label); - kfree(pin->rclk_dev_name); kfree(pin); return ERR_PTR(ret); } @@ -644,10 +625,6 @@ void dpll_pin_put(struct dpll_pin *pin) xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); xa_erase(&dpll_pin_xa, pin->id); - kfree(pin->prop.board_label); - kfree(pin->prop.panel_label); - kfree(pin->prop.package_label); - kfree(pin->prop.freq_supported); kfree(pin->rclk_dev_name); kfree(pin); } @@ -773,7 +750,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, unsigned long i, stop; int ret; - if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX)) + if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX)) return -EINVAL; ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); if (ret) diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 874999e1bfb7..b857562d2048 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -53,7 +53,7 @@ struct dpll_device { * @module: module of creator * @dpll_refs: hold referencees to dplls that pin is registered with * @pin_refs: hold references to pins that pin is registered with - * @prop: properties given by registerer + * @prop: pointer to pin properties given by registerer * @rclk_dev_name: holds name of device when pin can recover clock from it * @refcount: refcount **/ @@ -64,7 +64,7 @@ struct dpll_pin { struct module *module; struct xarray dpll_refs; struct xarray parent_refs; - struct dpll_pin_properties prop; + const struct dpll_pin_properties *prop; char *rclk_dev_name; refcount_t refcount; }; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index e002d2d99e12..6c3dd73dffbf 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -163,17 +163,17 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, const struct dpll_pin *pin, return -EMSGSIZE; if (!dump_freq_supported) return 0; - for (fs = 0; fs < pin->prop.freq_supported_num; fs++) { + for (fs = 0; fs < pin->prop->freq_supported_num; fs++) { nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); if (!nest) return -EMSGSIZE; - freq = pin->prop.freq_supported[fs].min; + freq = pin->prop->freq_supported[fs].min; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), &freq, 0)) { nla_nest_cancel(msg, nest); return -EMSGSIZE; } - freq = pin->prop.freq_supported[fs].max; + freq = pin->prop->freq_supported[fs].max; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), &freq, 0)) { nla_nest_cancel(msg, nest); @@ -270,6 +270,7 @@ static int dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) { + const struct dpll_pin_properties *prop = pin->prop; int ret; ret = dpll_msg_add_pin_handle(msg, pin); @@ -280,19 +281,19 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(pin->clock_id), &pin->clock_id, 0)) return -EMSGSIZE; - if (pin->prop.board_label && - nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, pin->prop.board_label)) + if (prop->board_label && + nla_put_string(msg, DPLL_A_PIN_BOARD_LABEL, prop->board_label)) return -EMSGSIZE; - if (pin->prop.panel_label && - nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, pin->prop.panel_label)) + if (prop->panel_label && + nla_put_string(msg, DPLL_A_PIN_PANEL_LABEL, prop->panel_label)) return -EMSGSIZE; - if (pin->prop.package_label && + if (prop->package_label && nla_put_string(msg, DPLL_A_PIN_PACKAGE_LABEL, - pin->prop.package_label)) + prop->package_label)) return -EMSGSIZE; - if (nla_put_u8(msg, DPLL_A_PIN_TYPE, pin->prop.type)) + if (nla_put_u8(msg, DPLL_A_PIN_TYPE, prop->type)) return -EMSGSIZE; - if (nla_put_u32(msg, DPLL_A_PIN_DPLL_CAPS, pin->prop.capabilities)) + if (nla_put_u32(msg, DPLL_A_PIN_DPLL_CAPS, prop->capabilities)) return -EMSGSIZE; ret = dpll_msg_add_pin_freq(msg, pin, ref, extack, true); if (ret && ret != -EOPNOTSUPP) @@ -385,9 +386,9 @@ static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) { int fs; - for (fs = 0; fs < pin->prop.freq_supported_num; fs++) - if (freq >= pin->prop.freq_supported[fs].min && - freq <= pin->prop.freq_supported[fs].max) + for (fs = 0; fs < pin->prop->freq_supported_num; fs++) + if (freq >= pin->prop->freq_supported[fs].min && + freq <= pin->prop->freq_supported[fs].max) return true; return false; } @@ -429,7 +430,7 @@ dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, struct dpll_pin *parent; unsigned long i; - if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop.capabilities)) + if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop->capabilities)) return -EOPNOTSUPP; parent = xa_load(&dpll_pin_xa, parent_idx); if (!parent) @@ -462,7 +463,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, const struct dpll_pin_ops *ops; struct dpll_pin_ref *ref; - if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop.capabilities)) + if (!(DPLL_PIN_CAPS_STATE_CAN_CHANGE & pin->prop->capabilities)) return -EOPNOTSUPP; ref = xa_load(&pin->dpll_refs, dpll->device_idx); if (!ref) @@ -484,7 +485,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, { const struct dpll_pin_ops *ops; struct dpll_pin_ref *ref; - if (!(DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE & pin->prop.capabilities)) + if (!(DPLL_PIN_CAPS_PRIORITY_CAN_CHANGE & pin->prop->capabilities)) return -EOPNOTSUPP; ref = xa_load(&pin->dpll_refs, dpll->device_idx); if (!ref) @@ -508,7 +509,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct nlattr *a, struct dpll_pin_ref *ref; unsigned long i; - if (!(DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE & pin->prop.capabilities)) + if (!(DPLL_PIN_CAPS_DIRECTION_CAN_CHANGE & pin->prop->capabilities)) return -EOPNOTSUPP; xa_for_each(&pin->dpll_refs, i, ref) { @@ -640,23 +641,25 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, { bool board_match, panel_match, package_match; struct dpll_pin *pin_match = NULL, *pin; + const struct dpll_pin_properties *prop; bool cid_match, mod_match, type_match; unsigned long i; xa_for_each(&dpll_pin_xa, i, pin) { if (xa_empty(&pin->dpll_refs)) continue; + prop = pin->prop; cid_match = clock_id ? pin->clock_id == clock_id : true; mod_match = mod_name_attr ? !nla_strcmp(mod_name_attr, pin->module->name) : true; - type_match = type ? pin->prop.type == type : true; - board_match = board_label && pin->prop.board_label ? - !nla_strcmp(board_label, pin->prop.board_label) : true; - panel_match = panel_label && pin->prop.panel_label ? - !nla_strcmp(panel_label, pin->prop.panel_label) : true; - package_match = package_label && pin->prop.package_label ? + type_match = type ? prop->type == type : true; + board_match = board_label && prop->board_label ? + !nla_strcmp(board_label, prop->board_label) : true; + panel_match = panel_label && prop->panel_label ? + !nla_strcmp(panel_label, prop->panel_label) : true; + package_match = package_label && prop->package_label ? !nla_strcmp(package_label, - pin->prop.package_label) : true; + prop->package_label) : true; if (cid_match && mod_match && type_match && board_match && panel_match && package_match) { if (pin_match) diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 388b97c01a85..08f37abf34b5 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -178,10 +178,11 @@ void dpll_device_unregister(struct dpll_device *dpll, * @clock_id: a system unique number of a device * @dev_driver_id: index of dpll device on parent device * @module: register module - * @pin_prop: constant properities of a pin + * @prop: constant properities of a pin, shall be not freed during pin's + * lifetime * - * find existing pin with given clock_id, @dev_driver_id and module, or create new - * and returen its reference. + * Find existing pin with given @clock_id, @dev_driver_id and @module, or create + * new and return its reference. * * Returns: * * pointer to initialized pin - success From bcd8745eecb977f9c3b977c5e92a9252712a203b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 15:11:33 +0200 Subject: [PATCH 81/93] dpll: core: verify pin/dpll owner on registering pin Verify if pin being registered belongs to the same instance of dpll by checking if they share clock_id and owner module. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 8685c2eb0103..5094506cfdc8 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -687,7 +687,11 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, int ret; mutex_lock(&dpll_lock); - ret = __dpll_pin_register(dpll, pin, ops, priv, rclk_name); + if (WARN_ON(!(dpll->module == pin->module && + dpll->clock_id == pin->clock_id))) + ret = -EFAULT; + else + ret = __dpll_pin_register(dpll, pin, ops, priv, rclk_name); mutex_unlock(&dpll_lock); return ret; From 8315be83b0c4e45c1feb18848659a4e4736714f0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 15:15:19 +0200 Subject: [PATCH 82/93] dpll: core: remove const arg modifier for helper _priv functions Do not use const modifier for arguments of helper get private data functions. Xarray macro doesn't allow to find elements which are const, remove the modifier and a cast which is no longer needed. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 16 ++++++++-------- drivers/dpll/dpll_core.h | 8 +++----- drivers/dpll/dpll_netlink.c | 16 ++++++++-------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 5094506cfdc8..21e3cfb1bb44 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -843,11 +843,11 @@ dpll_device_registration_first(struct dpll_device *dpll) * Context: shall be called under a lock (dpll_lock) * Return: pointer to the first registration priv data */ -void *dpll_priv(const struct dpll_device *dpll) +void *dpll_priv(struct dpll_device *dpll) { struct dpll_device_registration *reg; - reg = dpll_device_registration_first((struct dpll_device *) dpll); + reg = dpll_device_registration_first(dpll); return reg->priv; } @@ -892,13 +892,13 @@ dpll_pin_registration_first(struct dpll_pin_ref *ref) * Context: shall be called under a lock (dpll_lock) * Return: pointer to the data */ -void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, - const struct dpll_pin *pin) +void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, + struct dpll_pin *pin) { struct dpll_pin_registration *reg; struct dpll_pin_ref *ref; - ref = xa_load((struct xarray *)&dpll->pin_refs, pin->pin_idx); + ref = xa_load(&dpll->pin_refs, pin->pin_idx); if (!ref) return NULL; reg = dpll_pin_registration_first(ref); @@ -913,13 +913,13 @@ void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, * Context: shall be called under a lock (dpll_lock) * Return: pointer to the data */ -void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, - const struct dpll_pin *pin) +void *dpll_pin_on_pin_priv(struct dpll_pin *parent, + struct dpll_pin *pin) { struct dpll_pin_registration *reg; struct dpll_pin_ref *ref; - ref = xa_load((struct xarray *)&pin->parent_refs, parent->pin_idx); + ref = xa_load(&pin->parent_refs, parent->pin_idx); if (!ref) return NULL; reg = dpll_pin_registration_first(ref); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index b857562d2048..c5cf3dd1b549 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -91,11 +91,9 @@ struct dpll_pin_ref { refcount_t refcount; }; -void *dpll_priv(const struct dpll_device *dpll); -void *dpll_pin_on_dpll_priv(const struct dpll_device *dpll, - const struct dpll_pin *pin); -void *dpll_pin_on_pin_priv(const struct dpll_pin *parent, - const struct dpll_pin *pin); +void *dpll_priv(struct dpll_device *dpll); +void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, struct dpll_pin *pin); +void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin); const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll); struct dpll_device *dpll_device_get_by_id(int id); diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 6c3dd73dffbf..e5d0e3a26469 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -84,12 +84,12 @@ dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll, } static int -dpll_msg_add_pin_prio(struct sk_buff *msg, const struct dpll_pin *pin, +dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); - const struct dpll_device *dpll = ref->dpll; + struct dpll_device *dpll = ref->dpll; u32 prio; if (!ops->prio_get) @@ -104,12 +104,12 @@ dpll_msg_add_pin_prio(struct sk_buff *msg, const struct dpll_pin *pin, } static int -dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, const struct dpll_pin *pin, +dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); - const struct dpll_device *dpll = ref->dpll; + struct dpll_device *dpll = ref->dpll; enum dpll_pin_state state; if (!ops->state_on_dpll_get) @@ -124,12 +124,12 @@ dpll_msg_add_pin_on_dpll_state(struct sk_buff *msg, const struct dpll_pin *pin, } static int -dpll_msg_add_pin_direction(struct sk_buff *msg, const struct dpll_pin *pin, +dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); - const struct dpll_device *dpll = ref->dpll; + struct dpll_device *dpll = ref->dpll; enum dpll_pin_direction direction; if (!ops->direction_get) @@ -144,12 +144,12 @@ dpll_msg_add_pin_direction(struct sk_buff *msg, const struct dpll_pin *pin, } static int -dpll_msg_add_pin_freq(struct sk_buff *msg, const struct dpll_pin *pin, +dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack, bool dump_freq_supported) { const struct dpll_pin_ops *ops = dpll_pin_ops(ref); - const struct dpll_device *dpll = ref->dpll; + struct dpll_device *dpll = ref->dpll; struct nlattr *nest; u64 freq; int fs; From 6a65b04e6968ff4b1aa6a5eec5d5810eef92c62c Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 15:47:06 +0200 Subject: [PATCH 83/93] dpll: core: remove function declaration _get_by_name() The function was removed in previous commits, remove the declaration. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index c5cf3dd1b549..2ee21cf66c10 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -97,8 +97,6 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin); const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll); struct dpll_device *dpll_device_get_by_id(int id); -struct dpll_device *dpll_device_get_by_name(const char *bus_name, - const char *dev_name); const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref); struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs); extern struct xarray dpll_device_xa; From 9e81cef747f10fb4290092218a86cf750f6e48c2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 15:49:23 +0200 Subject: [PATCH 84/93] dpll:core: update SPDX headers Use current year, use same format for all the headers. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.h | 3 ++- drivers/dpll/dpll_netlink.c | 3 ++- drivers/dpll/dpll_netlink.h | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 2ee21cf66c10..f43a3942bbdd 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Intel and affiliates */ #ifndef __DPLL_CORE_H__ diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index e5d0e3a26469..b9db0739e573 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -2,7 +2,8 @@ /* * Generic netlink for DPLL management framework * - * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Intel and affiliates * */ #include diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h index 3227f4707900..20d40c34b268 100644 --- a/drivers/dpll/dpll_netlink.h +++ b/drivers/dpll/dpll_netlink.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2021 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Meta Platforms, Inc. and affiliates + * Copyright (c) 2023 Intel and affiliates */ /** From 7ecf49b73b64c801921935bb1d3343e348a6cc35 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 19:57:40 +0200 Subject: [PATCH 85/93] dpll: core: parse netlink set attributes with nlattr array Instead of parsing attributes as a stream of attributes, parse them as an nlattr array, while using dedicated functions. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 91 +++++++++++++------------------------ 1 file changed, 31 insertions(+), 60 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index b9db0739e573..ff592f834864 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -531,67 +531,46 @@ static int dpll_pin_parent_set(struct dpll_pin *pin, struct nlattr *parent_nest, struct netlink_ext_ack *extack) { - bool state_present = false, prio_present = false; - bool parent_dpll = false, parent_pin = false; - u32 parent_idx, dpll_idx, prio; + struct nlattr *tb[DPLL_A_MAX + 1]; + u32 ppin_idx, pdpll_idx, prio; enum dpll_pin_state state; struct dpll_pin_ref *ref; struct dpll_device *dpll; - struct nlattr *a; - int rem, ret; + int ret; - nla_for_each_nested(a, parent_nest, rem) { - switch (nla_type(a)) { - case DPLL_A_ID: - dpll_idx = nla_get_u32(a); - parent_dpll = true; - break; - case DPLL_A_PIN_ID: - parent_idx = nla_get_u32(a); - parent_pin = true; - break; - case DPLL_A_PIN_STATE: - state = nla_get_u8(a); - state_present = true; - break; - case DPLL_A_PIN_PRIO: - prio = nla_get_u32(a); - prio_present = true; - break; - default: - break; - } - } - if (parent_pin && !state_present) { - NL_SET_ERR_MSG(extack, "pin state is missing"); - return -EINVAL; - } - if (parent_dpll && !(state_present || prio_present)) { - NL_SET_ERR_MSG(extack, "both pin state and prio are missing"); + nla_parse_nested(tb, DPLL_A_MAX, parent_nest, + NULL, extack); + if ((tb[DPLL_A_ID] && tb[DPLL_A_PIN_ID]) || + !(tb[DPLL_A_ID] || tb[DPLL_A_PIN_ID])) { + NL_SET_ERR_MSG(extack, "one parent id expected"); return -EINVAL; } - if (parent_pin) { - ret = dpll_pin_on_pin_state_set(pin, parent_idx, state, extack); - if (ret) - return ret; - } else if (parent_dpll) { - dpll = xa_load(&dpll_device_xa, dpll_idx); + if (tb[DPLL_A_ID]) { + pdpll_idx = nla_get_u32(tb[DPLL_A_ID]); + dpll = xa_load(&dpll_device_xa, pdpll_idx); if (!dpll) return -EINVAL; ref = xa_load(&pin->dpll_refs, dpll->device_idx); if (!ref) return -EINVAL; - if (state_present) { - + if (tb[DPLL_A_PIN_STATE]) { + state = nla_get_u8(tb[DPLL_A_PIN_STATE]); ret = dpll_pin_state_set(dpll, pin, state, extack); if (ret) return ret; } - if (prio_present) { + if (tb[DPLL_A_PIN_PRIO]) { + prio = nla_get_u8(tb[DPLL_A_PIN_PRIO]); ret = dpll_pin_prio_set(dpll, pin, prio, extack); if (ret) return ret; } + } else if (tb[DPLL_A_PIN_ID]) { + ppin_idx = nla_get_u32(tb[DPLL_A_PIN_ID]); + state = nla_get_u8(tb[DPLL_A_PIN_STATE]); + ret = dpll_pin_on_pin_state_set(pin, ppin_idx, state, extack); + if (ret) + return ret; } return 0; @@ -887,27 +866,19 @@ static int dpll_set_from_nlattr(struct dpll_device *dpll, struct genl_info *info) { const struct dpll_device_ops *ops = dpll_device_ops(dpll); - struct nlattr *attr; - enum dpll_mode mode; - int rem, ret = 0; - - nla_for_each_attr(attr, genlmsg_data(info->genlhdr), - genlmsg_len(info->genlhdr), rem) { - switch (nla_type(attr)) { - case DPLL_A_MODE: - mode = nla_get_u8(attr); + struct nlattr *tb[DPLL_A_MAX + 1]; + int ret = 0; - ret = ops->mode_set(dpll, dpll_priv(dpll), mode, - info->extack); - if (ret) - return ret; - break; - default: - break; - } + nla_parse(tb, DPLL_A_MAX, genlmsg_data(info->genlhdr), + genlmsg_len(info->genlhdr), NULL, info->extack); + if (tb[DPLL_A_MODE]) { + ret = ops->mode_set(dpll, dpll_priv(dpll), + nla_get_u8(tb[DPLL_A_MODE]), info->extack); + if (ret) + return ret; } - return ret; + return 0; } int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info) From 329efc7dc6d8f6a7682b112786ddb91a2e29d48d Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:27:16 +0200 Subject: [PATCH 86/93] dpll: spec: remove rclk-dev-name aatribute The attribute is no longer needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- Documentation/netlink/specs/dpll.yaml | 7 ------- drivers/dpll/dpll_nl.c | 5 ++--- drivers/dpll/dpll_nl.h | 4 ++-- include/uapi/linux/dpll.h | 1 - 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index c5dde74b8bab..67b267d0ba34 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -250,9 +250,6 @@ attribute-sets: type: nest multi-attr: true nested-attributes: pin-parent - - - name: pin-rclk-device - type: string - name: pin-dpll-caps type: u32 @@ -275,9 +272,6 @@ attribute-sets: - name: pin-id type: u32 - - - name: pin-rclk-device - type: string - name: pin-frequency-range @@ -422,7 +416,6 @@ operations: - pin-frequency - pin-frequency-supported - pin-parent - - pin-rclk-device - pin-dpll-caps dump: diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index fd61ca2ed157..f5d1245deed9 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -8,16 +8,15 @@ #include "dpll_nl.h" -#include +#include /* Common nested types */ -const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1] = { +const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_STATE + 1] = { [DPLL_A_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_MAX(NLA_U8, 2), [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, [DPLL_A_PIN_STATE] = NLA_POLICY_MAX(NLA_U8, 3), [DPLL_A_PIN_ID] = { .type = NLA_U32, }, - [DPLL_A_PIN_RCLK_DEVICE] = { .type = NLA_NUL_STRING, }, }; /* DPLL_CMD_DEVICE_ID_GET - do */ diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 806efeff4c1d..54d493778888 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -9,10 +9,10 @@ #include #include -#include +#include /* Common nested types */ -extern const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_RCLK_DEVICE + 1]; +extern const struct nla_policy dpll_pin_parent_nl_policy[DPLL_A_PIN_STATE + 1]; int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 96c34e1bfb18..f078062ec832 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -155,7 +155,6 @@ enum dpll_a { DPLL_A_PIN_PRIO, DPLL_A_PIN_STATE, DPLL_A_PIN_PARENT, - DPLL_A_PIN_RCLK_DEVICE, DPLL_A_PIN_DPLL_CAPS, __DPLL_A_MAX, From 233db77134d38a9882bfe01532aa6caad1108ce7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:29:45 +0200 Subject: [PATCH 87/93] dpll: core: remove rclk-dev-name aatribute The attribute is no longer needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 28 ++++++---------------------- drivers/dpll/dpll_netlink.c | 4 ---- include/linux/dpll.h | 6 ++---- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 21e3cfb1bb44..50228dcfdd0c 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -625,7 +625,6 @@ void dpll_pin_put(struct dpll_pin *pin) xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); xa_erase(&dpll_pin_xa, pin->id); - kfree(pin->rclk_dev_name); kfree(pin); } } @@ -633,22 +632,16 @@ EXPORT_SYMBOL_GPL(dpll_pin_put); static int __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, - const struct dpll_pin_ops *ops, void *priv, - const char *rclk_device_name) + const struct dpll_pin_ops *ops, void *priv) { int ret; if (WARN_ON(!ops)) return -EINVAL; - if (rclk_device_name && !pin->rclk_dev_name) { - pin->rclk_dev_name = kstrdup(rclk_device_name, GFP_KERNEL); - if (!pin->rclk_dev_name) - return -ENOMEM; - } ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv); if (ret) - goto rclk_free; + return ret; ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv); if (ret) goto ref_pin_del; @@ -659,8 +652,6 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, ref_pin_del: dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv); -rclk_free: - kfree(pin->rclk_dev_name); return ret; } @@ -670,7 +661,6 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, * @pin: pointer to a dpll pin * @ops: ops for a dpll pin ops * @priv: pointer to private information of owner - * @rclk_device: pointer to recovered clock device * * Context: Acquires a lock (dpll_lock) * Return: @@ -680,10 +670,8 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, */ int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, - const struct dpll_pin_ops *ops, void *priv, - struct device *rclk_device) + const struct dpll_pin_ops *ops, void *priv) { - const char *rclk_name = rclk_device ? dev_name(rclk_device) : NULL; int ret; mutex_lock(&dpll_lock); @@ -691,7 +679,7 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, dpll->clock_id == pin->clock_id))) ret = -EFAULT; else - ret = __dpll_pin_register(dpll, pin, ops, priv, rclk_name); + ret = __dpll_pin_register(dpll, pin, ops, priv); mutex_unlock(&dpll_lock); return ret; @@ -734,7 +722,6 @@ EXPORT_SYMBOL_GPL(dpll_pin_unregister); * @pin: pointer to a pin * @ops: ops for a dpll pin * @priv: pointer to private information of owner - * @rclk_device: pointer to recovered clock device * * Register a pin with a parent pin, create references between them and * between newly registered pin and dplls connected with a parent pin. @@ -747,8 +734,7 @@ EXPORT_SYMBOL_GPL(dpll_pin_unregister); * * -EPERM if parent is not allowed */ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, - const struct dpll_pin_ops *ops, void *priv, - struct device *rclk_device) + const struct dpll_pin_ops *ops, void *priv) { struct dpll_pin_ref *ref; unsigned long i, stop; @@ -762,9 +748,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, refcount_inc(&pin->refcount); xa_for_each(&parent->dpll_refs, i, ref) { mutex_lock(&dpll_lock); - ret = __dpll_pin_register(ref->dpll, pin, ops, priv, - rclk_device ? - dev_name(rclk_device) : NULL); + ret = __dpll_pin_register(ref->dpll, pin, ops, priv); mutex_unlock(&dpll_lock); if (ret) { stop = i; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index ff592f834864..716a3b9bfd7d 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -299,10 +299,6 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_msg_add_pin_freq(msg, pin, ref, extack, true); if (ret && ret != -EOPNOTSUPP) return ret; - if (pin->rclk_dev_name) - if (nla_put_string(msg, DPLL_A_PIN_RCLK_DEVICE, - pin->rclk_dev_name)) - return -EMSGSIZE; return 0; } diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 08f37abf34b5..65043b0b6645 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -210,8 +210,7 @@ struct dpll_pin * * -EBUSY - couldn't allocate id for a pin. */ int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, - const struct dpll_pin_ops *ops, void *priv, - struct device *rclk_device); + const struct dpll_pin_ops *ops, void *priv); /** * dpll_pin_unregister - deregister pin from a dpll device @@ -253,8 +252,7 @@ void dpll_pin_put(struct dpll_pin *pin); * * -EEXIST - pin already registered with this parent pin, */ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, - const struct dpll_pin_ops *ops, void *priv, - struct device *rclk_device); + const struct dpll_pin_ops *ops, void *priv); /** * dpll_pin_on_pin_register - register a pin to a muxed-type pin From 674a79eef96d34e16045414804c4ad1628397068 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:30:44 +0200 Subject: [PATCH 88/93] ice: dpll: remove rclk-dev-name attribute The attribute is no longer needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/intel/ice/ice_dpll.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 9a0c20071766..e2a122d2edcb 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1234,8 +1234,7 @@ ice_dpll_register_pins(struct dpll_device *dpll, struct ice_dpll_pin *pins, int ret, i; for (i = 0; i < count; i++) { - ret = dpll_pin_register(dpll, pins[i].pin, ops, - &pins[i], NULL); + ret = dpll_pin_register(dpll, pins[i].pin, ops, &pins[i]); if (ret) goto unregister_pins; } @@ -1344,7 +1343,6 @@ ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin, int start_idx, const struct dpll_pin_ops *ops) { struct ice_vsi *vsi = ice_get_main_vsi(pf); - struct device *dev = ice_pf_to_dev(pf); struct dpll_pin *parent; int ret, i; @@ -1359,7 +1357,7 @@ ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin, goto unregister_pins; } ret = dpll_pin_on_pin_register(parent, pf->dplls.rclk.pin, - ops, &pf->dplls.rclk, dev); + ops, &pf->dplls.rclk); if (ret) goto unregister_pins; } From 6c1b1381c7be330e6c94281a0252eaf17ae294ba Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:32:00 +0200 Subject: [PATCH 89/93] mlx5: dpll: remove rclk-dev-name attribute The attribute is no longer needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/net/ethernet/mellanox/mlx5/core/dpll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index fa261e1854a4..1c4f84bf917d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -343,7 +343,7 @@ static int mlx5_dpll_probe(struct auxiliary_device *adev, } err = dpll_pin_register(mdpll->dpll, mdpll->dpll_pin, - &mlx5_dpll_pins_ops, mdpll, NULL); + &mlx5_dpll_pins_ops, mdpll); if (err) goto err_put_dpll_pin; From 56744b3db6fd65fd8a8016d7e958c12d3ec099ae Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:32:22 +0200 Subject: [PATCH 90/93] ptp_ocp: dpll: remove rclk-dev-name attribute The attribute is no longer needed, remove it. Signed-off-by: Arkadiusz Kubalewski --- drivers/ptp/ptp_ocp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 440d1d8803bd..e9e331b3213e 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -4429,7 +4429,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_dpll; err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, - &bp->sma[i], NULL); + &bp->sma[i]); if (err) { dpll_pin_put(bp->sma[i].dpll_pin); goto out_dpll; From 8eee5e3dcc94446958896c897846ad646c48958b Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 20:33:08 +0200 Subject: [PATCH 91/93] dpll: core: remove redundant doxygen from dpll header Leave only one description of dpll subsystem interface functions in the drivers/dpll/dpll_core.c Signed-off-by: Arkadiusz Kubalewski --- include/linux/dpll.h | 139 ------------------------------------------- 1 file changed, 139 deletions(-) diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 65043b0b6645..8d085dc92cdd 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -128,176 +128,37 @@ static inline int dpll_msg_add_pin_handle(struct sk_buff *msg, struct dpll_pin * #endif -/** - * dpll_device_get - find or create dpll_device object - * @clock_id: a system unique number for a device - * @dev_driver_id: index of dpll device on parent device - * @module: register module - * - * Returns: - * * pointer to initialized dpll - success - * * NULL - memory allocation fail - */ struct dpll_device *dpll_device_get(u64 clock_id, u32 dev_driver_id, struct module *module); -/** - * dpll_device_put - caller drops reference to the device, free resources - * @dpll: dpll device pointer - * - * If all dpll_device_get callers drops their reference, the dpll device - * resources are freed. - */ void dpll_device_put(struct dpll_device *dpll); -/** - * dpll_device_register - register device, make it visible in the subsystem. - * @dpll: reference previously allocated with dpll_device_get - * @type: type of dpll - * @ops: callbacks - * @priv: private data of registerer - * - */ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type, const struct dpll_device_ops *ops, void *priv); -/** - * dpll_device_unregister - deregister registered dpll - * @dpll: pointer to dpll - * @ops: ops for a dpll device - * @priv: pointer to private information of owner - * - * Unregister the dpll from the subsystem, make it unavailable for netlink - * API users. - */ void dpll_device_unregister(struct dpll_device *dpll, const struct dpll_device_ops *ops, void *priv); -/** - * dpll_pin_get - get reference or create new pin object - * @clock_id: a system unique number of a device - * @dev_driver_id: index of dpll device on parent device - * @module: register module - * @prop: constant properities of a pin, shall be not freed during pin's - * lifetime - * - * Find existing pin with given @clock_id, @dev_driver_id and @module, or create - * new and return its reference. - * - * Returns: - * * pointer to initialized pin - success - * * NULL - memory allocation fail - */ struct dpll_pin *dpll_pin_get(u64 clock_id, u32 dev_driver_id, struct module *module, const struct dpll_pin_properties *prop); -/** - * dpll_pin_register - register pin with a dpll device - * @dpll: pointer to dpll object to register pin with - * @pin: pointer to allocated pin object being registered with dpll - * @ops: struct with pin ops callbacks - * @priv: private data pointer passed when calling callback ops - * @rclk_device: pointer to device struct if pin is used for recovery of a clock - * from that device - * - * Register previously allocated pin object with a dpll device. - * - * Return: - * * 0 - if pin was registered with a parent pin, - * * -ENOMEM - failed to allocate memory, - * * -EEXIST - pin already registered with this dpll, - * * -EBUSY - couldn't allocate id for a pin. - */ int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv); -/** - * dpll_pin_unregister - deregister pin from a dpll device - * @dpll: pointer to dpll object to deregister pin from - * @pin: pointer to allocated pin object being deregistered from dpll - * @ops: ops for a dpll pin ops - * @priv: pointer to private information of owner - * - * Deregister previously registered pin object from a dpll device. - * - */ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv); -/** - * dpll_pin_put - drop reference to a pin acquired with dpll_pin_get - * @pin: pointer to allocated pin - * - * Pins shall be deregistered from all dpll devices before putting them, - * otherwise the memory won't be freed. - */ void dpll_pin_put(struct dpll_pin *pin); -/** - * dpll_pin_on_pin_register - register a pin to a muxed-type pin - * @parent: parent pin pointer - * @pin: pointer to allocated pin object being registered with a parent pin - * @ops: struct with pin ops callbacks - * @priv: private data pointer passed when calling callback ops - * @rclk_device: pointer to device struct if pin is used for recovery of a clock - * from that device - * - * In case of multiplexed pins, allows registring them under a single - * parent pin. - * - * Return: - * * 0 - if pin was registered with a parent pin, - * * -ENOMEM - failed to allocate memory, - * * -EEXIST - pin already registered with this parent pin, - */ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv); -/** - * dpll_pin_on_pin_register - register a pin to a muxed-type pin - * @parent: parent pin pointer - * @pin: pointer to allocated pin object being registered with a parent pin - * @ops: struct with pin ops callbacks - * @priv: private data pointer passed when calling callback ops - * @rclk_device: pointer to device struct if pin is used for recovery of a clock - * from that device - * - * In case of multiplexed pins, allows registring them under a single - * parent pin. - * - * Return: - * * 0 - if pin was registered with a parent pin, - * * -ENOMEM - failed to allocate memory, - * * -EEXIST - pin already registered with this parent pin, - */ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin, const struct dpll_pin_ops *ops, void *priv); -/** - * dpll_device_change_ntf - notify on dpll device change - * @dpll: dpll device pointer - * - * Broadcast event to the netlink multicast registered listeners. - * - * Context: Takes and releases a dpll_xa_lock. - * Return: - * * 0 - success - * * negative - error - */ int dpll_device_change_ntf(struct dpll_device *dpll); -/** - * dpll_device_change_ntf - notify on dpll device change - * @dpll: dpll device pointer - * - * Broadcast event to the netlink multicast registered listeners. - * - * Context: Takes and releases a dpll_xa_lock. - * Return: - * * 0 - success - * * negative - error - */ int dpll_pin_change_ntf(struct dpll_pin *pin); #endif From dce7633fc38b1c0e18f90ca75a4bc817c07ed0ee Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 22:33:06 +0200 Subject: [PATCH 92/93] dpll: core: use module_name() to get name of module Previously module->name was used, but it is only available when CONFIG_MODULE is defined. Instead use module_name() which allows to compile dpll subsystem without CONFIG_MODULE defined. Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_netlink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 716a3b9bfd7d..a03f4ec45556 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -277,7 +277,7 @@ dpll_cmd_pin_fill_details(struct sk_buff *msg, struct dpll_pin *pin, ret = dpll_msg_add_pin_handle(msg, pin); if (ret) return ret; - if (nla_put_string(msg, DPLL_A_MODULE_NAME, pin->module->name)) + if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(pin->module))) return -EMSGSIZE; if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(pin->clock_id), &pin->clock_id, 0)) @@ -355,7 +355,7 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, ret = dpll_msg_add_dev_handle(msg, dpll); if (ret) return ret; - if (nla_put_string(msg, DPLL_A_MODULE_NAME, dpll->module->name)) + if (nla_put_string(msg, DPLL_A_MODULE_NAME, module_name(dpll->module))) return -EMSGSIZE; if (nla_put_64bit(msg, DPLL_A_CLOCK_ID, sizeof(dpll->clock_id), &dpll->clock_id, 0)) @@ -626,8 +626,9 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, continue; prop = pin->prop; cid_match = clock_id ? pin->clock_id == clock_id : true; - mod_match = mod_name_attr ? - !nla_strcmp(mod_name_attr, pin->module->name) : true; + mod_match = mod_name_attr && module_name(pin->module) ? + !nla_strcmp(mod_name_attr, + module_name(pin->module)) : true; type_match = type ? prop->type == type : true; board_match = board_label && prop->board_label ? !nla_strcmp(board_label, prop->board_label) : true; @@ -804,8 +805,9 @@ dpll_device_find(u64 clock_id, struct nlattr *mod_name_attr, xa_for_each_marked(&dpll_device_xa, i, dpll, DPLL_REGISTERED) { cid_match = clock_id ? dpll->clock_id == clock_id : true; - mod_match = mod_name_attr ? - !nla_strcmp(mod_name_attr, dpll->module->name) : true; + mod_match = mod_name_attr && module_name(dpll->module) ? + !nla_strcmp(mod_name_attr, + module_name(dpll->module)) : true; type_match = type ? dpll->type == type : true; if (cid_match && mod_match && type_match) { if (dpll_match) From d3124fa9f5f57529edc689428953ef47ed5b8177 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Tue, 6 Jun 2023 23:17:41 +0200 Subject: [PATCH 93/93] dpll: core: fix kdocs Fix docs of dpll core files after checking with helper script: ./scripts/kernel-doc -none $DPLL_FILES Signed-off-by: Arkadiusz Kubalewski --- drivers/dpll/dpll_core.c | 12 ++++++++---- drivers/dpll/dpll_core.h | 14 ++++++-------- drivers/dpll/dpll_netlink.h | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 50228dcfdd0c..ee515b7c18be 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -137,7 +137,9 @@ dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, /** * dpll_xa_ref_pin_del - remove reference of a pin from xarray * @xa_pins: dpll_pin_ref xarray holding pins - * @pin: pointer to a pin + * @pin: pointer to a pin being removed + * @ops: pointer to ops of pin being removed + * @priv: pointer to private data of registerer who invoked pin removal * * Decrement refcount of existing pin reference on given xarray. * If all registrations are lifted delete the reference and free its memory. @@ -243,6 +245,8 @@ dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, * dpll_xa_ref_dpll_del - remove reference of a dpll from xarray * @xa_dplls: dpll_pin_ref xarray holding dplls * @dpll: pointer to a dpll to remove + * @ops: pointer to ops of dpll being removed + * @priv: pointer to private data of registerer who invoked dpll removal * * Decrement refcount of existing dpll reference on given xarray. * If all references are dropped, delete the reference and free its memory. @@ -276,8 +280,8 @@ dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, /** * dpll_xa_ref_dpll_find - find dpll reference on xarray - * @xa_dplls: dpll_pin_ref xarray holding dplls - * @dpll: pointer to a dpll + * @xa_refs: dpll_pin_ref xarray holding dpll references + * @dpll: pointer to a dpll being searched * * Search for dpll-pin ops reference struct of a given dpll on given xarray. * @@ -611,7 +615,7 @@ EXPORT_SYMBOL_GPL(dpll_pin_get); /** * dpll_pin_put - decrease the refcount and free memory if possible - * @dpll: dpll_device struct pointer + * @pin: pointer to a pin to be put * * Drop reference for a pin, if all references are gone, delete pin object. * diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index f43a3942bbdd..ef95e272937c 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -21,18 +21,16 @@ struct dpll_device_registration { }; /** - * struct dpll_device - structure for a DPLL device + * struct dpll_device - stores DPLL device internal data * @id: unique id number for each device given by kernel * @device_idx: id given by dev driver * @clock_id: unique identifier (clock_id) of a dpll * @module: module of creator - * @ops: operations this &dpll_device supports - * @lock: mutex to serialize operations * @type: type of a dpll - * @pins: list of pointers to pins registered with this dpll + * @pin_refs: stores pins registered within a dpll * @mode_supported_mask: mask of supported modes * @refcount: refcount - * @priv: pointer to private information of owner + * @registration_list: list of registered ops and priv data of dpll owners **/ struct dpll_device { u32 id; @@ -52,8 +50,8 @@ struct dpll_device { * @pin_idx: index of a pin given by dev driver * @clock_id: clock_id of creator * @module: module of creator - * @dpll_refs: hold referencees to dplls that pin is registered with - * @pin_refs: hold references to pins that pin is registered with + * @dpll_refs: hold referencees to dplls pin was registered with + * @parent_refs: hold references to parent pins pin was registered with * @prop: pointer to pin properties given by registerer * @rclk_dev_name: holds name of device when pin can recover clock from it * @refcount: refcount @@ -80,7 +78,7 @@ struct dpll_pin_registration { * struct dpll_pin_ref - structure for referencing either dpll or pins * @dpll: pointer to a dpll * @pin: pointer to a pin - * @registration_list list of ops and priv data registered with the ref + * @registration_list: list of ops and priv data registered with the ref * @refcount: refcount **/ struct dpll_pin_ref { diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h index 20d40c34b268..b5f9bfc88c9e 100644 --- a/drivers/dpll/dpll_netlink.h +++ b/drivers/dpll/dpll_netlink.h @@ -23,7 +23,7 @@ int dpll_device_create_ntf(struct dpll_device *dpll); int dpll_device_delete_ntf(struct dpll_device *dpll); /** - * dpll_pin_delete_ntf - notify that the pin has been deleted + * dpll_pin_create_ntf - notify that the pin has been created * @pin: registered pin pointer * * Context: caller shall hold dpll_xa_lock.