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

Reply via email to