You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/04/10 12:59:33 UTC

[GitHub] [incubator-nuttx] pkarashchenko commented on a diff in pull request #6020: arch/riscv: Add mtimer driver

pkarashchenko commented on code in PR #6020:
URL: https://github.com/apache/incubator-nuttx/pull/6020#discussion_r846776194


##########
arch/risc-v/src/common/riscv_mtimer.c:
##########
@@ -0,0 +1,306 @@
+/****************************************************************************
+ * arch/risc-v/src/common/riscv_mtimer.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+
+#include "riscv_mtimer.h"
+#include "riscv_internal.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure provides the private representation of the "lower-half"
+ * driver state structure.  This structure must be cast-compatible with the
+ * oneshot_lowerhalf_s structure.
+ */
+
+struct riscv_mtimer_lowerhalf_s
+{
+  struct oneshot_lowerhalf_s lower;
+  uintptr_t                  mtime;
+  uintptr_t                  mtimecmp;
+  uint64_t                   freq;
+  uint64_t                   alarm;
+  oneshot_callback_t         callback;
+  void                       *arg;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int riscv_mtimer_max_delay(struct oneshot_lowerhalf_s *lower,
+                                  struct timespec *ts);
+static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower,
+                              oneshot_callback_t callback, void *arg,
+                              const struct timespec *ts);
+static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower,
+                               struct timespec *ts);
+static int riscv_mtimer_current(struct oneshot_lowerhalf_s *lower,
+                                struct timespec *ts);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct oneshot_operations_s g_riscv_mtimer_ops =
+{
+  .max_delay = riscv_mtimer_max_delay,
+  .start     = riscv_mtimer_start,
+  .cancel    = riscv_mtimer_cancel,
+  .current   = riscv_mtimer_current,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint64_t riscv_mtimer_get_mtime(struct riscv_mtimer_lowerhalf_s *priv)
+{
+#ifdef CONFIG_ARCH_RV64
+  return getreg64(priv->mtime);
+#else
+  uint32_t hi;
+  uint32_t lo;
+
+  do
+    {
+      hi = getreg32(priv->mtime + 4);
+      lo = getreg32(priv->mtime);
+    }
+  while (getreg32(priv->mtime + 4) != hi);
+
+  return ((uint64_t)hi << 32) | lo;
+#endif
+}
+
+static void riscv_mtimer_set_mtimecmp(struct riscv_mtimer_lowerhalf_s *priv,
+                                      uint64_t value)
+{
+#ifdef CONFIG_ARCH_RV64
+  putreg64(value, priv->mtimecmp);
+#else
+  putreg32(UINT32_MAX, priv->mtimecmp + 4);
+  putreg32(value, priv->mtimecmp);
+  putreg32(value >> 32, priv->mtimecmp + 4);
+#endif
+}
+
+/****************************************************************************
+ * Name: riscv_mtimer_max_delay
+ *
+ * Description:
+ *   Determine the maximum delay of the one-shot timer
+ *
+ * Input Parameters:
+ *   lower   An instance of the lower-half oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           oneshot_initialize();
+ *   ts      The location in which to return the maximum delay.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+static int riscv_mtimer_max_delay(struct oneshot_lowerhalf_s *lower,
+                                  struct timespec *ts)
+{
+  ts->tv_sec  = UINT32_MAX;
+  ts->tv_nsec = NSEC_PER_SEC - 1;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: riscv_mtimer_start
+ *
+ * Description:
+ *   Start the oneshot timer
+ *
+ * Input Parameters:
+ *   lower   An instance of the lower-half oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           oneshot_initialize();
+ *   handler The function to call when when the oneshot timer expires.
+ *   arg     An opaque argument that will accompany the callback.
+ *   ts      Provides the duration of the one shot timer.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower,
+                              oneshot_callback_t callback, void *arg,
+                              const struct timespec *ts)
+{
+  struct riscv_mtimer_lowerhalf_s *priv =
+    (struct riscv_mtimer_lowerhalf_s *)lower;
+  uint64_t mtime = riscv_mtimer_get_mtime(priv);
+
+  priv->alarm = mtime + ts->tv_sec * priv->freq +
+                ts->tv_nsec * priv->freq / NSEC_PER_SEC;
+  if (priv->alarm < mtime)
+    {
+      priv->alarm = UINT64_MAX;
+    }
+
+  priv->callback = callback;
+  priv->arg      = arg;
+
+  riscv_mtimer_set_mtimecmp(priv, priv->alarm);
+  return 0;
+}
+
+/****************************************************************************
+ * Name: riscv_mtimer_cancel
+ *
+ * Description:
+ *   Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ *   NOTE: This function may execute at a high rate with no timer running (as
+ *   when pre-emption is enabled and disabled).
+ *
+ * Input Parameters:
+ *   lower   Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           oneshot_initialize();
+ *   ts      The location in which to return the time remaining on the
+ *           oneshot timer.  A time of zero is returned if the timer is
+ *           not running.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  A call to up_timer_cancel() when
+ *   the timer is not active should also return success; a negated errno
+ *   value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower,
+                               struct timespec *ts)
+{
+  struct riscv_mtimer_lowerhalf_s *priv =
+    (struct riscv_mtimer_lowerhalf_s *)lower;
+  uint64_t mtime;
+
+  riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
+
+  mtime = riscv_mtimer_get_mtime(priv);
+  if (priv->alarm > mtime)
+    {
+      uint64_t nsec = (priv->alarm - mtime) *
+                      NSEC_PER_SEC / priv->freq;
+
+      ts->tv_sec  = nsec / NSEC_PER_SEC;
+      ts->tv_nsec = nsec % NSEC_PER_SEC;
+    }
+  else
+    {
+      ts->tv_sec  = 0;
+      ts->tv_nsec = 0;
+    }
+
+  priv->alarm    = 0;
+  priv->callback = NULL;
+  priv->arg      = NULL;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: riscv_mtimer_current
+ *
+ * Description:
+ *  Get the current time.
+ *
+ * Input Parameters:
+ *   lower   Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           oneshot_initialize();
+ *   ts      The location in which to return the current time. A time of zero
+ *           is returned for the initialization moment.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success, a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+static int riscv_mtimer_current(struct oneshot_lowerhalf_s *lower,
+                                struct timespec *ts)
+{
+  struct riscv_mtimer_lowerhalf_s *priv =
+    (struct riscv_mtimer_lowerhalf_s *)lower;
+  uint64_t mtime = riscv_mtimer_get_mtime(priv);
+  uint64_t nsec = mtime * NSEC_PER_SEC / priv->freq;
+
+  ts->tv_sec  = nsec / NSEC_PER_SEC;
+  ts->tv_nsec = nsec % NSEC_PER_SEC;
+
+  return 0;
+}
+
+static int riscv_mtimer_interrupt(int irq, void *context, void *arg)
+{
+  struct riscv_mtimer_lowerhalf_s *priv = arg;
+
+  riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
+  if (priv->callback != NULL)
+    {
+      priv->callback(&priv->lower, priv->arg);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+struct oneshot_lowerhalf_s *
+riscv_mtimer_initialize(uintptr_t mtime, uintptr_t mtimecmp,
+                        int irq, uint64_t freq)
+{
+  struct riscv_mtimer_lowerhalf_s *priv;
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv != NULL)
+    {
+      priv->lower.ops = &g_riscv_mtimer_ops;
+      priv->mtime     = mtime;
+      priv->mtimecmp  = mtimecmp;
+      priv->freq      = freq;
+
+      riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
+      irq_attach(irq, riscv_mtimer_interrupt, priv);
+      up_enable_irq(irq);
+    }
+
+  return &priv->lower;

Review Comment:
   So i case if `kmm_zalloc` we will de-reference NULL pointer?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org