summaryrefslogtreecommitdiffstats
path: root/sys/contrib/octeon-sdk/cvmx-tim.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/octeon-sdk/cvmx-tim.h')
-rw-r--r--sys/contrib/octeon-sdk/cvmx-tim.h333
1 files changed, 333 insertions, 0 deletions
diff --git a/sys/contrib/octeon-sdk/cvmx-tim.h b/sys/contrib/octeon-sdk/cvmx-tim.h
new file mode 100644
index 0000000..3cad58b
--- /dev/null
+++ b/sys/contrib/octeon-sdk/cvmx-tim.h
@@ -0,0 +1,333 @@
+/***********************license start***************
+ * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
+ * reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+
+ * * Neither the name of Cavium Inc. nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+
+ * This Software, including technical data, may be subject to U.S. export control
+ * laws, including the U.S. Export Administration Act and its associated
+ * regulations, and may be subject to export or import regulations in other
+ * countries.
+
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+ * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+ * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
+ * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
+ * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
+ * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
+ * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
+ * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
+ * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+ ***********************license end**************************************/
+
+
+
+
+
+
+
+/**
+ * @file
+ *
+ * Interface to the hardware work queue timers.
+ *
+`* <hr>$Revision: 70030 $<hr>
+ */
+
+#ifndef __CVMX_TIM_H__
+#define __CVMX_TIM_H__
+
+#include "cvmx-clock.h"
+#include "cvmx-fpa.h"
+#include "cvmx-wqe.h"
+
+#include "executive-config.h"
+#ifdef CVMX_ENABLE_TIMER_FUNCTIONS
+#include "cvmx-config.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CVMX_TIM_NUM_TIMERS (OCTEON_IS_MODEL(OCTEON_CN68XX) ? 64 : 16)
+#define CVMX_TIM_NUM_BUCKETS 2048
+
+typedef enum
+{
+ CVMX_TIM_STATUS_SUCCESS = 0,
+ CVMX_TIM_STATUS_NO_MEMORY = -1,
+ CVMX_TIM_STATUS_TOO_FAR_AWAY = -2,
+ CVMX_TIM_STATUS_BUSY = -3
+} cvmx_tim_status_t;
+
+/**
+ * Each timer bucket contains a list of work queue entries to
+ * schedule when the timer fires. The list is implemented as
+ * a linked list of blocks. Each block contains an array of
+ * work queue entries followed by a next block pointer. Since
+ * these blocks are dynamically allocated off of a hardware
+ * memory pool, there actual size isn't known compile time.
+ * The next block pointer is stored in the last 8 bytes of
+ * the memory block.
+ */
+typedef struct cvmx_tim_entry_chunk
+{
+ volatile uint64_t entries[0];
+} cvmx_tim_entry_chunk_t;
+
+/**
+ * Each timer contains an array of buckets. Each bucket
+ * represents the list of work queue entries that should be
+ * scheduled when the timer fires. The first 3 entries are used
+ * byt the hardware.
+ */
+typedef struct
+{
+ volatile uint64_t first_chunk_addr;
+ volatile uint32_t num_entries; /**< Zeroed by HW after traversing list */
+ volatile uint32_t chunk_remainder;/**< Zeroed by HW after traversing list */
+
+ // the remaining 16 bytes are not touched by hardware
+ volatile cvmx_tim_entry_chunk_t *last_chunk;
+ uint64_t pad;
+} cvmx_tim_bucket_entry_t;
+
+/**
+ * Structure representing an individual timer. Each timer has
+ * a timer period, a memory management pool, and a list of
+ * buckets.
+ */
+typedef struct
+{
+ cvmx_tim_bucket_entry_t*bucket; /**< The timer buckets. Array of [CVMX_TIM_NUM_TIMERS][CVMX_TIM_NUM_BUCKETS] */
+ uint64_t tick_cycles; /**< How long a bucket represents */
+ uint64_t start_time; /**< Time the timer started in cycles */
+ uint32_t bucket_shift; /**< How long a bucket represents in ms */
+ uint32_t num_buckets; /**< How many buckets per wheel */
+ uint32_t max_ticks; /**< maximum number of ticks allowed for timer */
+} cvmx_tim_t;
+
+/**
+ * Structure used to store state information needed to delete
+ * an already scheduled timer entry. An instance of this
+ * structure must be passed to cvmx_tim_add_entry in order
+ * to be able to delete an entry later with
+ * cvmx_tim_delete_entry.
+ *
+ * NOTE: This structure should be considered opaque by the application,
+ * and the application should not access its members
+ */
+typedef struct
+{
+ uint64_t commit_cycles; /**< After this time the timer can't be changed */
+ uint64_t * timer_entry_ptr;/**< Where the work entry is. Zero this
+ location to delete the entry */
+} cvmx_tim_delete_t;
+
+/**
+ * Global structure holding the state of all timers.
+ */
+extern cvmx_tim_t cvmx_tim;
+
+
+
+
+#ifdef CVMX_ENABLE_TIMER_FUNCTIONS
+/**
+ * Setup a timer for use. Must be called before the timer
+ * can be used.
+ *
+ * @param tick Time between each bucket in microseconds. This must not be
+ * smaller than 1024/(clock frequency in MHz).
+ * @param max_ticks The maximum number of ticks the timer must be able
+ * to schedule in the future. There are guaranteed to be enough
+ * timer buckets such that:
+ * number of buckets >= max_ticks.
+ * @return Zero on success. Negative on error. Failures are possible
+ * if the number of buckets needed is too large or memory
+ * allocation fails for creating the buckets.
+ */
+int cvmx_tim_setup(uint64_t tick, uint64_t max_ticks);
+#endif
+
+/**
+ * Start the hardware timer processing
+ */
+extern void cvmx_tim_start(void);
+
+
+/**
+ * Stop the hardware timer processing. Timers stay configured.
+ */
+extern void cvmx_tim_stop(void);
+
+
+/**
+ * Stop the timer. After this the timer must be setup again
+ * before use.
+ */
+#ifdef CVMX_ENABLE_TIMER_FUNCTIONS
+extern void cvmx_tim_shutdown(void);
+#endif
+
+#ifdef CVMX_ENABLE_TIMER_FUNCTIONS
+/**
+ * Add a work queue entry to the timer.
+ *
+ * @param work_entry Work queue entry to add.
+ * @param ticks_from_now
+ * @param delete_info
+ * Optional pointer where to store information needed to
+ * delete the timer entry. If non NULL information needed
+ * to delete the timer entry before it fires is stored here.
+ * If you don't need to be able to delete the timer, pass
+ * NULL.
+ * @return Result return code
+ */
+static inline cvmx_tim_status_t cvmx_tim_add_entry(cvmx_wqe_t *work_entry, uint64_t ticks_from_now, cvmx_tim_delete_t *delete_info)
+{
+ cvmx_tim_bucket_entry_t* work_bucket_ptr;
+ uint64_t work_bucket;
+ volatile uint64_t * tim_entry_ptr; /* pointer to wqe address in timer chunk */
+ uint64_t entries_per_chunk;
+
+ const uint64_t cycles = cvmx_clock_get_count(CVMX_CLOCK_TIM); /* Get our reference time early for accuracy */
+ const uint64_t core_num = cvmx_get_core_num(); /* One timer per processor, so use this to select */
+
+ /* Make sure the specified time won't wrap our bucket list */
+ if (ticks_from_now > cvmx_tim.max_ticks)
+ {
+ cvmx_dprintf("cvmx_tim_add_entry: Tried to schedule work too far away.\n");
+ return CVMX_TIM_STATUS_TOO_FAR_AWAY;
+ }
+
+ /* Since we have no way to synchronize, we can't update a timer that is
+ being used by the hardware. Two buckets forward should be safe */
+ if (ticks_from_now < 2)
+ {
+ cvmx_dprintf("cvmx_tim_add_entry: Tried to schedule work too soon. Delaying it.\n");
+ ticks_from_now = 2;
+ }
+
+ /* Get the bucket this work queue entry should be in. Remember the bucket
+ array is circular */
+ work_bucket = (((ticks_from_now * cvmx_tim.tick_cycles) + cycles - cvmx_tim.start_time)
+ >> cvmx_tim.bucket_shift);
+
+ work_bucket_ptr = cvmx_tim.bucket + core_num * cvmx_tim.num_buckets + (work_bucket & (cvmx_tim.num_buckets - 1));
+ entries_per_chunk = (CVMX_FPA_TIMER_POOL_SIZE/8 - 1);
+
+ /* Check if we have room to add this entry into the existing list */
+ if (work_bucket_ptr->chunk_remainder)
+ {
+ /* Adding the work entry to the end of the existing list */
+ tim_entry_ptr = &(work_bucket_ptr->last_chunk->entries[entries_per_chunk - work_bucket_ptr->chunk_remainder]);
+ *tim_entry_ptr = cvmx_ptr_to_phys(work_entry);
+ work_bucket_ptr->chunk_remainder--;
+ work_bucket_ptr->num_entries++;
+ }
+ else
+ {
+ /* Current list is either completely empty or completely full. We need
+ to allocate a new chunk for storing this work entry */
+ cvmx_tim_entry_chunk_t *new_chunk = (cvmx_tim_entry_chunk_t *)cvmx_fpa_alloc(CVMX_FPA_TIMER_POOL);
+ if (new_chunk == NULL)
+ {
+ cvmx_dprintf("cvmx_tim_add_entry: Failed to allocate memory for new chunk.\n");
+ return CVMX_TIM_STATUS_NO_MEMORY;
+ }
+
+ /* Does a chunk currently exist? We have to check num_entries since
+ the hardware doesn't NULL out the chunk pointers on free */
+ if (work_bucket_ptr->num_entries)
+ {
+ /* This chunk must be appended to an existing list by putting
+ ** its address in the last spot of the existing chunk. */
+ work_bucket_ptr->last_chunk->entries[entries_per_chunk] = cvmx_ptr_to_phys(new_chunk);
+ work_bucket_ptr->num_entries++;
+ }
+ else
+ {
+ /* This is the very first chunk. Add it */
+ work_bucket_ptr->first_chunk_addr = cvmx_ptr_to_phys(new_chunk);
+ work_bucket_ptr->num_entries = 1;
+ }
+ work_bucket_ptr->last_chunk = new_chunk;
+ work_bucket_ptr->chunk_remainder = entries_per_chunk - 1;
+ tim_entry_ptr = &(new_chunk->entries[0]);
+ *tim_entry_ptr = cvmx_ptr_to_phys(work_entry);
+ }
+
+ /* If the user supplied a delete info structure then fill it in */
+ if (delete_info)
+ {
+ /* It would be very bad to delete a timer entry after, or during the
+ timer's processing. During the processing could yield unpredicatable
+ results, but after would always be bad. Modifying the entry after
+ processing means we would be changing data in a buffer that has been
+ freed, and possible allocated again. For this reason we store a
+ commit cycle count in the delete structure. If we are after this
+ count we will refuse to delete the timer entry. */
+ delete_info->commit_cycles = cycles + (ticks_from_now - 2) * cvmx_tim.tick_cycles;
+ delete_info->timer_entry_ptr = (uint64_t *)tim_entry_ptr; /* Cast to non-volatile type */
+ }
+
+ CVMX_SYNCWS; /* Make sure the hardware timer unit can access valid data from L2 */
+
+ return CVMX_TIM_STATUS_SUCCESS;
+}
+#endif
+
+
+/**
+ * Delete a timer entry scheduled using cvmx_tim_add_entry.
+ * Deleting a timer will fail if it has already triggered or
+ * might be in progress. The actual state of the work queue
+ * entry isn't changed. You need to dispose of it properly.
+ *
+ * @param delete_info
+ * Structure passed to cvmx_tim_add_entry to store the
+ * information needed to delete a timer entry.
+ * @return CVMX_TIM_STATUS_BUSY if the timer was not deleted, otherwise
+ * CVMX_TIM_STATUS_SUCCESS.
+ */
+static inline cvmx_tim_status_t cvmx_tim_delete_entry(cvmx_tim_delete_t *delete_info)
+{
+ const uint64_t cycles = cvmx_clock_get_count(CVMX_CLOCK_TIM);
+
+ if ((int64_t)(cycles - delete_info->commit_cycles) < 0)
+ {
+ /* Timer is far enough away. Safe to delete */
+ *delete_info->timer_entry_ptr = 0;
+ return CVMX_TIM_STATUS_SUCCESS;
+ }
+ else
+ {
+ /* Timer is passed the commit time. It cannot be stopped */
+ return CVMX_TIM_STATUS_BUSY;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CVMX_TIM_H__
OpenPOWER on IntegriCloud