From: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com> Used by synce_dev to acquire current state of its DPLL.
Co-developed-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com> Signed-off-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com> Co-developed-by: Piotr Kwapulinski <piotr.kwapulin...@intel.com> Signed-off-by: Piotr Kwapulinski <piotr.kwapulin...@intel.com> Co-developed-by: Michal Michalik <michal.micha...@intel.com> Signed-off-by: Michal Michalik <michal.micha...@intel.com> Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com> --- v4: - changed order of patch in patch-series - changed naming 'Sync-E' -> 'SyncE' - change 'DPLL' -> 'EEC' to be more HW agnostic v3: rebase patch series v2: updated license headers synce_dev_ctrl.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ synce_dev_ctrl.h | 64 +++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 synce_dev_ctrl.c create mode 100644 synce_dev_ctrl.h diff --git a/synce_dev_ctrl.c b/synce_dev_ctrl.c new file mode 100644 index 0000000..6285714 --- /dev/null +++ b/synce_dev_ctrl.c @@ -0,0 +1,153 @@ +/** + * @file synce_dev_ctrl.c + * @brief Interface for acquiring SyncE capable device EEC state changes + * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation + * @note SPDX-License-Identifier: GPL-2.0+ + */ +#include <errno.h> +#include <stdlib.h> +#include "print.h" +#include "synce_dev_ctrl.h" + +#define EEC_STATE_STR_RETURN_SIZE 0xff +struct synce_dev_ctrl { + const char *eec_get_state_cmd; + struct eec_state_str ess; +}; + +static int eec_str_state_to_enum(struct synce_dev_ctrl *dc, char *str_state, + enum eec_state *enum_state) +{ + if (!strncmp(str_state, dc->ess.holdover, EEC_STATE_STR_RETURN_SIZE)) { + *enum_state = EEC_HOLDOVER; + } else if (!strncmp(str_state, dc->ess.locked_ho, + EEC_STATE_STR_RETURN_SIZE)) { + *enum_state = EEC_LOCKED_HO_ACQ; + } else if (!strncmp(str_state, dc->ess.locked, + EEC_STATE_STR_RETURN_SIZE)) { + *enum_state = EEC_LOCKED; + } else if (!strncmp(str_state, dc->ess.freerun, + EEC_STATE_STR_RETURN_SIZE)) { + *enum_state = EEC_FREERUN; + } else if (!strncmp(str_state, dc->ess.invalid, + EEC_STATE_STR_RETURN_SIZE)) { + *enum_state = EEC_INVALID; + } else { + *enum_state = EEC_UNKNOWN; + } + + if (*enum_state == EEC_UNKNOWN) { + pr_err("eec state missing for str_state: '%s'", str_state); + return -EINVAL; + } + + return 0; +} + +static int get_eec_state_from_cmd(struct synce_dev_ctrl *dc, + enum eec_state *state) +{ + char buf[EEC_STATE_STR_RETURN_SIZE] = {0}, *c; + FILE *fp; + int ret; + + fp = popen(dc->eec_get_state_cmd, "r"); + if (!fp) { + pr_err("failed open process: '%s'", dc->eec_get_state_cmd); + return EEC_UNKNOWN; + } + + if (!fgets(buf, sizeof(buf), fp)) { + pr_err("failed read process output: '%s'", dc->eec_get_state_cmd); + goto out; + } + + c = buf; + while (*c != '\0') { + if (*(++c) == '\n') { + *c = '\0'; + } + } + +out: + ret = pclose(fp); + if (ret) { + pr_err("process '%s' exit status: %d", + dc->eec_get_state_cmd, ret); + } + + return ret ? EEC_UNKNOWN : eec_str_state_to_enum(dc, buf, state); +} + +int synce_dev_ctrl_get_state(struct synce_dev_ctrl *dc, + enum eec_state *state) +{ + int ret = -EINVAL; + + if (!dc) { + pr_err("%s: dc is NULL", __func__); + return ret; + } + + if (!state) { + pr_err("%s: state is NULL", __func__); + return ret; + } + + if (!dc->eec_get_state_cmd) { + pr_err("%s: dc->eec_get_state_cmd is NULL", __func__); + return ret; + } + + ret = get_eec_state_from_cmd(dc, state); + if (ret || *state < EEC_INVALID || *state > EEC_HOLDOVER) { + return ret; + } + + return 0; +} + +struct synce_dev_ctrl *synce_dev_ctrl_create(void) +{ + struct synce_dev_ctrl *dc = malloc(sizeof(struct synce_dev_ctrl)); + return dc; +} + +int synce_dev_ctrl_init(struct synce_dev_ctrl *dc, const char *dev_name, + const char *eec_get_state_cmd, + struct eec_state_str *ess) +{ + if (!dc || !dev_name) { + return -ENODEV; + } + + if (!eec_get_state_cmd) { + pr_err("failure: eec_get_state_cmd is NULL on %s", dev_name); + return -ENXIO; + } + if (!ess->holdover) { + pr_err("failure: ess.holdover is NULL on %s", dev_name); + return -ENXIO; + } + if (!ess->locked_ho) { + pr_err("failure: ess.locked_ho is NULL on %s", dev_name); + return -ENXIO; + } + if (!ess->locked) { + pr_err("failure: ess.locked is NULL on %s", dev_name); + return -ENXIO; + } + if (!ess->freerun) { + pr_err("failure: ess.freerun is NULL on %s", dev_name); + return -ENXIO; + } + if (!ess->invalid) { + pr_err("failure: ess.invalid is NULL on %s", dev_name); + return -ENXIO; + } + + dc->eec_get_state_cmd = eec_get_state_cmd; + dc->ess = *ess; + + return 0; +} diff --git a/synce_dev_ctrl.h b/synce_dev_ctrl.h new file mode 100644 index 0000000..2523153 --- /dev/null +++ b/synce_dev_ctrl.h @@ -0,0 +1,64 @@ +/** + * @file synce_dev_ctrl.h + * @brief Interface for acquiring SyncE capable device EEC state changes + * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation + * @note SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef HAVE_SYNCE_DEV_CTRL_H +#define HAVE_SYNCE_DEV_CTRL_H + +/* possible EEC states */ +enum eec_state { + EEC_UNKNOWN = -1, + EEC_INVALID, + EEC_FREERUN, + EEC_LOCKED, + EEC_LOCKED_HO_ACQ, + EEC_HOLDOVER, +}; + +/* possibe EEC state strings */ +struct eec_state_str { + const char *holdover; + const char *locked_ho; + const char *locked; + const char *freerun; + const char *invalid; +}; + +/* Opaque type */ +struct synce_dev_ctrl; + +/** + * Acquire current state of EEC of SyncE capable device. + * + * @param dc Instance of EEC device controller + * @param state State acquired from the device + * @return Zero on success, non-zero if failure + */ +int synce_dev_ctrl_get_state(struct synce_dev_ctrl *dc, + enum eec_state *state); + +/** + * Initialize EEC device controller instance. + * + * @param dc Instance of EEC device controller to be + * initialized + * @param dev_name Name of device + * @param eec_get_state_cmd A command to obtain current eec state + * @param ess Pointer to a struct holding valid eec state + strings + * @return Zero on success, non-zero if failure + */ +int synce_dev_ctrl_init(struct synce_dev_ctrl *dc, const char *dev_name, + const char *eec_get_state_cmd, + struct eec_state_str *ess); + +/** + * Allocate memory for a single EEC device controller instance. + * + * @return Pointer to allocated instance or NULL if allocation failed + */ +struct synce_dev_ctrl *synce_dev_ctrl_create(void); + +#endif /* HAVE_SYNCE_DEV_CTRL_H */ -- 2.9.5 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel