]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dpll: zl3073x: Cache reference monitor status
authorIvan Vecera <ivecera@redhat.com>
Thu, 13 Nov 2025 07:41:02 +0000 (08:41 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 18 Nov 2025 04:23:37 +0000 (20:23 -0800)
Instead of reading the ZL_REG_REF_MON_STATUS register every time
the reference status is needed, cache this value in the zl3073x_ref
struct.

This is achieved by:
* Adding a mon_status field to struct zl3073x_ref
* Introducing zl3073x_dev_ref_status_update() to read the status for
  all references into this new cache field
* Calling this update function from the periodic work handler
* Adding zl3073x_ref_is_status_ok() and zl3073x_dev_ref_is_status_ok()
  helpers to check the cached value
* Refactoring all callers in dpll.c to use the new
  zl3073x_dev_ref_is_status_ok() helper, removing direct register reads

This change consolidates all status register reads into a single periodic
function and reduces I/O bus traffic in dpll callbacks.

Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20251113074105.141379-4-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/dpll/zl3073x/core.c
drivers/dpll/zl3073x/core.h
drivers/dpll/zl3073x/dpll.c
drivers/dpll/zl3073x/ref.h

index 2f340f7eb9ec31b95b83a82c723fcfca98d67bbd..383e2397dd033e7071f74d608ba04f547162a495 100644 (file)
@@ -591,6 +591,21 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
        return rc;
 }
 
+static void
+zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev)
+{
+       int i, rc;
+
+       for (i = 0; i < ZL3073X_NUM_REFS; i++) {
+               rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i),
+                                    &zldev->ref[i].mon_status);
+               if (rc)
+                       dev_warn(zldev->dev,
+                                "Failed to get REF%u status: %pe\n", i,
+                                ERR_PTR(rc));
+       }
+}
+
 /**
  * zl3073x_ref_phase_offsets_update - update reference phase offsets
  * @zldev: pointer to zl3073x_dev structure
@@ -710,6 +725,9 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
        struct zl3073x_dpll *zldpll;
        int rc;
 
+       /* Update input references status */
+       zl3073x_dev_ref_status_update(zldev);
+
        /* Update DPLL-to-connected-ref phase offsets registers */
        rc = zl3073x_ref_phase_offsets_update(zldev, -1);
        if (rc)
index fe779fc77dd09df35efab32dc341a7dd62d8faf5..4148580d1f34340b9abb70918f525266e4b84660 100644 (file)
@@ -227,6 +227,21 @@ zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
        return zl3073x_ref_is_enabled(ref);
 }
 
+/*
+ * zl3073x_dev_ref_is_status_ok - check the given input reference status
+ * @zldev: pointer to zl3073x device
+ * @index: input reference index
+ *
+ * Return: true if the status is ok, false otherwise
+ */
+static inline bool
+zl3073x_dev_ref_is_status_ok(struct zl3073x_dev *zldev, u8 index)
+{
+       const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
+
+       return zl3073x_ref_is_status_ok(ref);
+}
+
 /**
  * zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by
  * @zldev: pointer to zl3073x device
index 62996f26e065fe8a8ae9522ecdde64caf12cf485..20c921d6f42cb27465f46bf7db01193c1f73ad00 100644 (file)
@@ -497,19 +497,10 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
        if (rc)
                return rc;
 
-       if (ZL3073X_DPLL_REF_IS_VALID(*ref)) {
-               u8 ref_status;
-
-               /* Read the reference monitor status */
-               rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(*ref),
-                                    &ref_status);
-               if (rc)
-                       return rc;
-
-               /* If the monitor indicates an error nothing is connected */
-               if (ref_status != ZL_REF_MON_STATUS_OK)
-                       *ref = ZL3073X_DPLL_REF_NONE;
-       }
+       /* If the monitor indicates an error nothing is connected */
+       if (ZL3073X_DPLL_REF_IS_VALID(*ref) &&
+           !zl3073x_dev_ref_is_status_ok(zldev, *ref))
+               *ref = ZL3073X_DPLL_REF_NONE;
 
        return 0;
 }
@@ -524,7 +515,7 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
        struct zl3073x_dpll *zldpll = dpll_priv;
        struct zl3073x_dev *zldev = zldpll->dev;
        struct zl3073x_dpll_pin *pin = pin_priv;
-       u8 conn_ref, ref, ref_status;
+       u8 conn_ref, ref;
        s64 ref_phase;
        int rc;
 
@@ -537,21 +528,9 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
         * monitor feature is disabled.
         */
        ref = zl3073x_input_pin_ref_get(pin->id);
-       if (!zldpll->phase_monitor && ref != conn_ref) {
-               *phase_offset = 0;
-
-               return 0;
-       }
-
-       /* Get this pin monitor status */
-       rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &ref_status);
-       if (rc)
-               return rc;
-
-       /* Report phase offset only if the input pin signal is present */
-       if (ref_status != ZL_REF_MON_STATUS_OK) {
+       if ((!zldpll->phase_monitor && ref != conn_ref) ||
+           !zl3073x_dev_ref_is_status_ok(zldev, ref)) {
                *phase_offset = 0;
-
                return 0;
        }
 
@@ -777,7 +756,7 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
 {
        struct zl3073x_dpll *zldpll = pin->dpll;
        struct zl3073x_dev *zldev = zldpll->dev;
-       u8 ref, ref_conn, status;
+       u8 ref, ref_conn;
        int rc;
 
        ref = zl3073x_input_pin_ref_get(pin->id);
@@ -797,20 +776,9 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
         * pin as selectable.
         */
        if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
-           pin->selectable) {
-               /* Read reference monitor status */
-               rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
-                                    &status);
-               if (rc)
-                       return rc;
-
-               /* If the monitor indicates errors report the reference
-                * as disconnected
-                */
-               if (status == ZL_REF_MON_STATUS_OK) {
-                       *state = DPLL_PIN_STATE_SELECTABLE;
-                       return 0;
-               }
+           zl3073x_dev_ref_is_status_ok(zldev, ref) && pin->selectable) {
+               *state = DPLL_PIN_STATE_SELECTABLE;
+               return 0;
        }
 
        /* Otherwise report the pin as disconnected */
@@ -2036,37 +2004,23 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
 
        ref = zl3073x_input_pin_ref_get(pin->id);
 
+       /* No phase offset if the ref monitor reports signal errors */
+       if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
+               return false;
+
        /* Select register to read phase offset value depending on pin and
         * phase monitor state:
         * 1) For connected pin use dpll_phase_err_data register
         * 2) For other pins use appropriate ref_phase register if the phase
-        *    monitor feature is enabled and reference monitor does not
-        *    report signal errors for given input pin
+        *    monitor feature is enabled.
         */
-       if (pin->pin_state == DPLL_PIN_STATE_CONNECTED) {
+       if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
                reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
-       } else if (zldpll->phase_monitor) {
-               u8 status;
-
-               /* Get reference monitor status */
-               rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
-                                    &status);
-               if (rc) {
-                       dev_err(zldev->dev,
-                               "Failed to read %s refmon status: %pe\n",
-                               pin->label, ERR_PTR(rc));
-
-                       return false;
-               }
-
-               if (status != ZL_REF_MON_STATUS_OK)
-                       return false;
-
+       else if (zldpll->phase_monitor)
                reg = ZL_REG_REF_PHASE(ref);
-       } else {
+       else
                /* The pin is not connected or phase monitor disabled */
                return false;
-       }
 
        /* Read measured phase offset value */
        rc = zl3073x_read_u48(zldev, reg, &phase_offset);
@@ -2105,22 +2059,14 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
 {
        struct zl3073x_dpll *zldpll = pin->dpll;
        struct zl3073x_dev *zldev = zldpll->dev;
-       u8 ref, status;
        s64 ffo;
-       int rc;
+       u8 ref;
 
        /* Get reference monitor status */
        ref = zl3073x_input_pin_ref_get(pin->id);
-       rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &status);
-       if (rc) {
-               dev_err(zldev->dev, "Failed to read %s refmon status: %pe\n",
-                       pin->label, ERR_PTR(rc));
-
-               return false;
-       }
 
        /* Do not report ffo changes if the reference monitor report errors */
-       if (status != ZL_REF_MON_STATUS_OK)
+       if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
                return false;
 
        /* Get the latest measured ref's ffo */
index e72f2c8750876084198224f91588b3717a5506c9..c4931e545d24d1167821ee0b3e5c372069d432f5 100644 (file)
@@ -14,10 +14,12 @@ struct zl3073x_dev;
  * struct zl3073x_ref - input reference state
  * @ffo: current fractional frequency offset
  * @config: reference config
+ * @mon_status: reference monitor status
  */
 struct zl3073x_ref {
        s64     ffo;
        u8      config;
+       u8      mon_status;
 };
 
 int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
@@ -63,4 +65,16 @@ zl3073x_ref_is_enabled(const struct zl3073x_ref *ref)
        return !!FIELD_GET(ZL_REF_CONFIG_ENABLE, ref->config);
 }
 
+/**
+ * zl3073x_ref_is_status_ok - check the given input reference status
+ * @ref: pointer to ref state
+ *
+ * Return: true if the status is ok, false otherwise
+ */
+static inline bool
+zl3073x_ref_is_status_ok(const struct zl3073x_ref *ref)
+{
+       return ref->mon_status == ZL_REF_MON_STATUS_OK;
+}
+
 #endif /* _ZL3073X_REF_H */