Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016, Intel Corporation |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions are met: |
| 7 | * * Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * * Redistributions in binary form must reproduce the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer in the |
| 11 | * documentation and/or other materials provided with the distribution. |
| 12 | * * Neither the name of the Intel Corporation nor the |
| 13 | * names of its contributors may be used to endorse or promote products |
| 14 | * derived from this software without specific prior written permission. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 26 | * POSSIBILITY OF SUCH DAMAGE. |
| 27 | * |
| 28 | * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> |
| 29 | * |
Pierre-Louis Bossart | f945809 | 2017-11-09 15:24:07 -0600 | [diff] [blame] | 30 | * Simple wait for event completion and signaling with timeouts. |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 31 | */ |
| 32 | |
| 33 | #ifndef __INCLUDE_WAIT__ |
| 34 | #define __INCLUDE_WAIT__ |
| 35 | |
| 36 | #include <stdint.h> |
| 37 | #include <errno.h> |
Liam Girdwood | 46f1220 | 2018-01-22 23:24:24 +0000 | [diff] [blame] | 38 | #include <arch/wait.h> |
Pierre-Louis Bossart | 81708a5 | 2018-04-04 18:46:50 -0500 | [diff] [blame] | 39 | #include <sof/debug.h> |
| 40 | #include <sof/work.h> |
| 41 | #include <sof/timer.h> |
| 42 | #include <sof/interrupt.h> |
| 43 | #include <sof/trace.h> |
| 44 | #include <sof/lock.h> |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 45 | #include <platform/interrupt.h> |
| 46 | |
Liam Girdwood | 8fe770c | 2017-10-19 17:32:42 +0100 | [diff] [blame] | 47 | #if DEBUG_LOCKS |
| 48 | #define wait_atomic_check \ |
| 49 | if (lock_dbg_atomic) { \ |
| 50 | trace_error_atomic(TRACE_CLASS_WAIT, "atm"); \ |
| 51 | } |
| 52 | #else |
| 53 | #define wait_atomic_check |
| 54 | #endif |
| 55 | |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 56 | typedef struct { |
| 57 | uint32_t complete; |
| 58 | struct work work; |
Yan Wang | 860292e | 2017-10-10 18:40:13 +0800 | [diff] [blame] | 59 | uint64_t timeout; |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 60 | } completion_t; |
| 61 | |
| 62 | void arch_wait_for_interrupt(int level); |
| 63 | |
| 64 | static inline void wait_for_interrupt(int level) |
| 65 | { |
| 66 | tracev_event(TRACE_CLASS_WAIT, "WFE"); |
Liam Girdwood | 8fe770c | 2017-10-19 17:32:42 +0100 | [diff] [blame] | 67 | wait_atomic_check; |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 68 | arch_wait_for_interrupt(level); |
| 69 | tracev_event(TRACE_CLASS_WAIT, "WFX"); |
| 70 | } |
| 71 | |
Yan Wang | 860292e | 2017-10-10 18:40:13 +0800 | [diff] [blame] | 72 | static uint64_t _wait_cb(void *data, uint64_t delay) |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 73 | { |
| 74 | volatile completion_t *wc = (volatile completion_t*)data; |
| 75 | |
| 76 | wc->timeout = 1; |
| 77 | return 0; |
| 78 | } |
| 79 | |
| 80 | static inline uint32_t wait_is_completed(completion_t *comp) |
| 81 | { |
| 82 | volatile completion_t *c = (volatile completion_t *)comp; |
| 83 | |
| 84 | return c->complete; |
| 85 | } |
| 86 | |
| 87 | static inline void wait_completed(completion_t *comp) |
| 88 | { |
| 89 | volatile completion_t *c = (volatile completion_t *)comp; |
| 90 | |
| 91 | c->complete = 1; |
| 92 | } |
| 93 | |
| 94 | static inline void wait_init(completion_t *comp) |
| 95 | { |
| 96 | volatile completion_t *c = (volatile completion_t *)comp; |
| 97 | |
| 98 | c->complete = 0; |
| 99 | work_init(&comp->work, _wait_cb, comp, WORK_ASYNC); |
| 100 | } |
| 101 | |
| 102 | static inline void wait_clear(completion_t *comp) |
| 103 | { |
| 104 | volatile completion_t *c = (volatile completion_t *)comp; |
| 105 | |
| 106 | c->complete = 0; |
| 107 | } |
| 108 | |
| 109 | /* simple interrupt based wait for completion */ |
| 110 | static inline void wait_for_completion(completion_t *comp) |
| 111 | { |
| 112 | /* check for completion after every wake from IRQ */ |
| 113 | while (comp->complete == 0) |
| 114 | wait_for_interrupt(0); |
| 115 | } |
| 116 | |
| 117 | |
| 118 | /* simple interrupt based wait for completion with timeout */ |
| 119 | static inline int wait_for_completion_timeout(completion_t *comp) |
| 120 | { |
| 121 | volatile completion_t *c = (volatile completion_t *)comp; |
| 122 | |
| 123 | work_schedule_default(&comp->work, comp->timeout); |
| 124 | comp->timeout = 0; |
| 125 | |
| 126 | /* check for completion after every wake from IRQ */ |
Liam Girdwood | d164e00 | 2017-08-10 15:23:17 +0100 | [diff] [blame] | 127 | while (1) { |
| 128 | |
Pierre-Louis Bossart | 090d4f4 | 2017-09-25 14:52:17 -0500 | [diff] [blame] | 129 | if (c->complete || c->timeout) |
Liam Girdwood | d164e00 | 2017-08-10 15:23:17 +0100 | [diff] [blame] | 130 | break; |
| 131 | |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 132 | wait_for_interrupt(0); |
| 133 | } |
| 134 | |
Liam Girdwood | d164e00 | 2017-08-10 15:23:17 +0100 | [diff] [blame] | 135 | /* did we complete */ |
| 136 | if (c->complete) { |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 137 | /* no timeout so cancel work and return 0 */ |
| 138 | work_cancel_default(&comp->work); |
| 139 | return 0; |
| 140 | } else { |
| 141 | /* timeout */ |
Ranjani Sridharan | 210989d | 2018-03-25 17:34:04 -0700 | [diff] [blame] | 142 | trace_error_value(c->timeout); |
| 143 | trace_error_value(c->complete); |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 144 | return -ETIME; |
| 145 | } |
| 146 | } |
| 147 | |
Tomasz Lauda | cd0044e | 2018-06-11 20:27:34 +0200 | [diff] [blame] | 148 | /** |
| 149 | * \brief Waits at least passed number of clocks. |
| 150 | * \param[in] number_of_clks Minimum number of clocks to wait. |
| 151 | */ |
| 152 | static inline void wait_delay(uint64_t number_of_clks) |
| 153 | { |
| 154 | uint64_t current = platform_timer_get(platform_timer); |
| 155 | |
| 156 | while ((platform_timer_get(platform_timer) - current) < number_of_clks) |
| 157 | idelay(PLATFORM_DEFAULT_DELAY); |
| 158 | } |
| 159 | |
Liam Girdwood | c0dfb4e | 2016-09-21 15:57:22 +0100 | [diff] [blame] | 160 | #endif |