qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/core/clock: introduce clock object

This object may be used to represent a clock inside a clock tree.

A clock may be connected to another clock so that it receives update,
through a callback, whenever the source/parent clock is updated.

Although only the root clock of a clock tree controls the values
(represented as periods) of all clocks in tree, each clock holds
a local state containing the current value so that it can be fetched
independently. It will allows us to fullfill migration requirements
by migrating each clock independently of others.

This is based on the original work of Frederic Konrad.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 20200406135251.157596-2-damien.hedde@greensocs.com
[PMM: Use uint64_t rather than unsigned long long in trace events;
the dtrace backend can't handle the latter]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+354
+1
hw/core/Makefile.objs
··· 7 7 common-obj-y += vmstate-if.o 8 8 # irq.o needed for qdev GPIO handling: 9 9 common-obj-y += irq.o 10 + common-obj-y += clock.o 10 11 11 12 common-obj-$(CONFIG_SOFTMMU) += reset.o 12 13 common-obj-$(CONFIG_SOFTMMU) += qdev-fw.o
+130
hw/core/clock.c
··· 1 + /* 2 + * Hardware Clocks 3 + * 4 + * Copyright GreenSocs 2016-2020 5 + * 6 + * Authors: 7 + * Frederic Konrad 8 + * Damien Hedde 9 + * 10 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 11 + * See the COPYING file in the top-level directory. 12 + */ 13 + 14 + #include "qemu/osdep.h" 15 + #include "hw/clock.h" 16 + #include "trace.h" 17 + 18 + #define CLOCK_PATH(_clk) (_clk->canonical_path) 19 + 20 + void clock_setup_canonical_path(Clock *clk) 21 + { 22 + g_free(clk->canonical_path); 23 + clk->canonical_path = object_get_canonical_path(OBJECT(clk)); 24 + } 25 + 26 + void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque) 27 + { 28 + clk->callback = cb; 29 + clk->callback_opaque = opaque; 30 + } 31 + 32 + void clock_clear_callback(Clock *clk) 33 + { 34 + clock_set_callback(clk, NULL, NULL); 35 + } 36 + 37 + void clock_set(Clock *clk, uint64_t period) 38 + { 39 + trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period), 40 + CLOCK_PERIOD_TO_NS(period)); 41 + clk->period = period; 42 + } 43 + 44 + static void clock_propagate_period(Clock *clk, bool call_callbacks) 45 + { 46 + Clock *child; 47 + 48 + QLIST_FOREACH(child, &clk->children, sibling) { 49 + if (child->period != clk->period) { 50 + child->period = clk->period; 51 + trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk), 52 + CLOCK_PERIOD_TO_NS(clk->period), 53 + call_callbacks); 54 + if (call_callbacks && child->callback) { 55 + child->callback(child->callback_opaque); 56 + } 57 + clock_propagate_period(child, call_callbacks); 58 + } 59 + } 60 + } 61 + 62 + void clock_propagate(Clock *clk) 63 + { 64 + assert(clk->source == NULL); 65 + trace_clock_propagate(CLOCK_PATH(clk)); 66 + clock_propagate_period(clk, true); 67 + } 68 + 69 + void clock_set_source(Clock *clk, Clock *src) 70 + { 71 + /* changing clock source is not supported */ 72 + assert(!clk->source); 73 + 74 + trace_clock_set_source(CLOCK_PATH(clk), CLOCK_PATH(src)); 75 + 76 + clk->period = src->period; 77 + QLIST_INSERT_HEAD(&src->children, clk, sibling); 78 + clk->source = src; 79 + clock_propagate_period(clk, false); 80 + } 81 + 82 + static void clock_disconnect(Clock *clk) 83 + { 84 + if (clk->source == NULL) { 85 + return; 86 + } 87 + 88 + trace_clock_disconnect(CLOCK_PATH(clk)); 89 + 90 + clk->source = NULL; 91 + QLIST_REMOVE(clk, sibling); 92 + } 93 + 94 + static void clock_initfn(Object *obj) 95 + { 96 + Clock *clk = CLOCK(obj); 97 + 98 + QLIST_INIT(&clk->children); 99 + } 100 + 101 + static void clock_finalizefn(Object *obj) 102 + { 103 + Clock *clk = CLOCK(obj); 104 + Clock *child, *next; 105 + 106 + /* clear our list of children */ 107 + QLIST_FOREACH_SAFE(child, &clk->children, sibling, next) { 108 + clock_disconnect(child); 109 + } 110 + 111 + /* remove us from source's children list */ 112 + clock_disconnect(clk); 113 + 114 + g_free(clk->canonical_path); 115 + } 116 + 117 + static const TypeInfo clock_info = { 118 + .name = TYPE_CLOCK, 119 + .parent = TYPE_OBJECT, 120 + .instance_size = sizeof(Clock), 121 + .instance_init = clock_initfn, 122 + .instance_finalize = clock_finalizefn, 123 + }; 124 + 125 + static void clock_register_types(void) 126 + { 127 + type_register_static(&clock_info); 128 + } 129 + 130 + type_init(clock_register_types)
+7
hw/core/trace-events
··· 27 27 resettable_phase_exit_exec(void *obj, const char *objtype, int has_method) "obj=%p(%s) method=%d" 28 28 resettable_phase_exit_end(void *obj, const char *objtype, unsigned count) "obj=%p(%s) count=%d" 29 29 resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)" 30 + 31 + # clock.c 32 + clock_set_source(const char *clk, const char *src) "'%s', src='%s'" 33 + clock_disconnect(const char *clk) "'%s'" 34 + clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64 35 + clock_propagate(const char *clk) "'%s'" 36 + clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d"
+216
include/hw/clock.h
··· 1 + /* 2 + * Hardware Clocks 3 + * 4 + * Copyright GreenSocs 2016-2020 5 + * 6 + * Authors: 7 + * Frederic Konrad 8 + * Damien Hedde 9 + * 10 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 11 + * See the COPYING file in the top-level directory. 12 + */ 13 + 14 + #ifndef QEMU_HW_CLOCK_H 15 + #define QEMU_HW_CLOCK_H 16 + 17 + #include "qom/object.h" 18 + #include "qemu/queue.h" 19 + 20 + #define TYPE_CLOCK "clock" 21 + #define CLOCK(obj) OBJECT_CHECK(Clock, (obj), TYPE_CLOCK) 22 + 23 + typedef void ClockCallback(void *opaque); 24 + 25 + /* 26 + * clock store a value representing the clock's period in 2^-32ns unit. 27 + * It can represent: 28 + * + periods from 2^-32ns up to 4seconds 29 + * + frequency from ~0.25Hz 2e10Ghz 30 + * Resolution of frequency representation decreases with frequency: 31 + * + at 100MHz, resolution is ~2mHz 32 + * + at 1Ghz, resolution is ~0.2Hz 33 + * + at 10Ghz, resolution is ~20Hz 34 + */ 35 + #define CLOCK_PERIOD_1SEC (1000000000llu << 32) 36 + 37 + /* 38 + * macro helpers to convert to hertz / nanosecond 39 + */ 40 + #define CLOCK_PERIOD_FROM_NS(ns) ((ns) * (CLOCK_PERIOD_1SEC / 1000000000llu)) 41 + #define CLOCK_PERIOD_TO_NS(per) ((per) / (CLOCK_PERIOD_1SEC / 1000000000llu)) 42 + #define CLOCK_PERIOD_FROM_HZ(hz) (((hz) != 0) ? CLOCK_PERIOD_1SEC / (hz) : 0u) 43 + #define CLOCK_PERIOD_TO_HZ(per) (((per) != 0) ? CLOCK_PERIOD_1SEC / (per) : 0u) 44 + 45 + /** 46 + * Clock: 47 + * @parent_obj: parent class 48 + * @period: unsigned integer representing the period of the clock 49 + * @canonical_path: clock path string cache (used for trace purpose) 50 + * @callback: called when clock changes 51 + * @callback_opaque: argument for @callback 52 + * @source: source (or parent in clock tree) of the clock 53 + * @children: list of clocks connected to this one (it is their source) 54 + * @sibling: structure used to form a clock list 55 + */ 56 + 57 + typedef struct Clock Clock; 58 + 59 + struct Clock { 60 + /*< private >*/ 61 + Object parent_obj; 62 + 63 + /* all fields are private and should not be modified directly */ 64 + 65 + /* fields */ 66 + uint64_t period; 67 + char *canonical_path; 68 + ClockCallback *callback; 69 + void *callback_opaque; 70 + 71 + /* Clocks are organized in a clock tree */ 72 + Clock *source; 73 + QLIST_HEAD(, Clock) children; 74 + QLIST_ENTRY(Clock) sibling; 75 + }; 76 + 77 + /** 78 + * clock_setup_canonical_path: 79 + * @clk: clock 80 + * 81 + * compute the canonical path of the clock (used by log messages) 82 + */ 83 + void clock_setup_canonical_path(Clock *clk); 84 + 85 + /** 86 + * clock_set_callback: 87 + * @clk: the clock to register the callback into 88 + * @cb: the callback function 89 + * @opaque: the argument to the callback 90 + * 91 + * Register a callback called on every clock update. 92 + */ 93 + void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque); 94 + 95 + /** 96 + * clock_clear_callback: 97 + * @clk: the clock to delete the callback from 98 + * 99 + * Unregister the callback registered with clock_set_callback. 100 + */ 101 + void clock_clear_callback(Clock *clk); 102 + 103 + /** 104 + * clock_set_source: 105 + * @clk: the clock. 106 + * @src: the source clock 107 + * 108 + * Setup @src as the clock source of @clk. The current @src period 109 + * value is also copied to @clk and its subtree but no callback is 110 + * called. 111 + * Further @src update will be propagated to @clk and its subtree. 112 + */ 113 + void clock_set_source(Clock *clk, Clock *src); 114 + 115 + /** 116 + * clock_set: 117 + * @clk: the clock to initialize. 118 + * @value: the clock's value, 0 means unclocked 119 + * 120 + * Set the local cached period value of @clk to @value. 121 + */ 122 + void clock_set(Clock *clk, uint64_t value); 123 + 124 + static inline void clock_set_hz(Clock *clk, unsigned hz) 125 + { 126 + clock_set(clk, CLOCK_PERIOD_FROM_HZ(hz)); 127 + } 128 + 129 + static inline void clock_set_ns(Clock *clk, unsigned ns) 130 + { 131 + clock_set(clk, CLOCK_PERIOD_FROM_NS(ns)); 132 + } 133 + 134 + /** 135 + * clock_propagate: 136 + * @clk: the clock 137 + * 138 + * Propagate the clock period that has been previously configured using 139 + * @clock_set(). This will update recursively all connected clocks. 140 + * It is an error to call this function on a clock which has a source. 141 + * Note: this function must not be called during device inititialization 142 + * or migration. 143 + */ 144 + void clock_propagate(Clock *clk); 145 + 146 + /** 147 + * clock_update: 148 + * @clk: the clock to update. 149 + * @value: the new clock's value, 0 means unclocked 150 + * 151 + * Update the @clk to the new @value. All connected clocks will be informed 152 + * of this update. This is equivalent to call @clock_set() then 153 + * @clock_propagate(). 154 + */ 155 + static inline void clock_update(Clock *clk, uint64_t value) 156 + { 157 + clock_set(clk, value); 158 + clock_propagate(clk); 159 + } 160 + 161 + static inline void clock_update_hz(Clock *clk, unsigned hz) 162 + { 163 + clock_update(clk, CLOCK_PERIOD_FROM_HZ(hz)); 164 + } 165 + 166 + static inline void clock_update_ns(Clock *clk, unsigned ns) 167 + { 168 + clock_update(clk, CLOCK_PERIOD_FROM_NS(ns)); 169 + } 170 + 171 + /** 172 + * clock_get: 173 + * @clk: the clk to fetch the clock 174 + * 175 + * @return: the current period. 176 + */ 177 + static inline uint64_t clock_get(const Clock *clk) 178 + { 179 + return clk->period; 180 + } 181 + 182 + static inline unsigned clock_get_hz(Clock *clk) 183 + { 184 + return CLOCK_PERIOD_TO_HZ(clock_get(clk)); 185 + } 186 + 187 + static inline unsigned clock_get_ns(Clock *clk) 188 + { 189 + return CLOCK_PERIOD_TO_NS(clock_get(clk)); 190 + } 191 + 192 + /** 193 + * clock_is_enabled: 194 + * @clk: a clock 195 + * 196 + * @return: true if the clock is running. 197 + */ 198 + static inline bool clock_is_enabled(const Clock *clk) 199 + { 200 + return clock_get(clk) != 0; 201 + } 202 + 203 + static inline void clock_init(Clock *clk, uint64_t value) 204 + { 205 + clock_set(clk, value); 206 + } 207 + static inline void clock_init_hz(Clock *clk, uint64_t value) 208 + { 209 + clock_set_hz(clk, value); 210 + } 211 + static inline void clock_init_ns(Clock *clk, uint64_t value) 212 + { 213 + clock_set_ns(clk, value); 214 + } 215 + 216 + #endif /* QEMU_HW_CLOCK_H */