diff mbox series

[v6,6/9] docs/clocks: add device's clock documentation

Message ID 20190904125531.27545-7-damien.hedde@greensocs.com (mailing list archive)
State New, archived
Headers show
Series Clock framework API | expand

Commit Message

Damien Hedde Sept. 4, 2019, 12:55 p.m. UTC
Add the documentation about the clock inputs and outputs in devices.

This is based on the original work of Frederic Konrad.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
---
 docs/devel/clock.txt | 246 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)
 create mode 100644 docs/devel/clock.txt

Comments

Peter Maydell Dec. 2, 2019, 3:17 p.m. UTC | #1
On Wed, 4 Sep 2019 at 13:56, Damien Hedde <damien.hedde@greensocs.com> wrote:
>
> Add the documentation about the clock inputs and outputs in devices.
>
> This is based on the original work of Frederic Konrad.
>
> Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
> ---
>  docs/devel/clock.txt | 246 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 246 insertions(+)
>  create mode 100644 docs/devel/clock.txt

Could you convert this to rst format, please?



> +Changing a clock output
> +=======================
> +
> +A device can change its outputs using the clock_set_frequency function. It
> +will trigger updates on every connected inputs.

"input"

> +
> +For example, let's say that we have an output clock "clkout" and we have a
> +pointer to it in the device state because we did the following in init phase:
> +dev->clkout = qdev_init_clock_out(DEVICE(dev), "clkout");
> +
> +Then at any time (apart from the cases listed below), it is possible to
> +change the clock value by doing:
> +clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Ghz */
> +This operation must be done while holding the qemu io lock.
> +
> +One can change clocks only when it is allowed to have side effects on other
> +objects. In consequence, it is forbidden:
> ++ during migration,
> ++ and in the init phase of reset.
> +
> +Forwarding clocks
> +=================
> +
> +Sometimes, one needs to forward, or inherit, a clock from another device.
> +Typically, when doing device composition, a device might expose a sub-device's
> +clock without interfering with it.
> +The function qdev_pass_clock() can be used to achieve this behaviour. Note, that

"Note that"

> +it is possible to expose the clock under a different name. This works for both
> +inputs or outputs.

"inputs and outputs"


> +Migration
> +=========
> +
> +Only the ClockIn object has a state. ClockOut is not concerned by migration.

"has any state".

"ClockOut has no state and does not need special handling for migration."

> +
> +In case the frequency of in input clock is needed for a device's migration,
> +this state must be migrated.

Are you trying to say that if an input clock is known to be a
fixed frequency we don't need to migrate anything? I wonder
if we need to worry about that or if we could/should just say that
input clocks should always be migrated.

> The VMSTATE_CLOCKIN macro defines an entry to
> +be added in a vmstate description.
> +
> +For example, if a device has a clock input and the device state looks like:
> +MyDeviceState {
> +    DeviceState parent_obj;
> +    ClockIn *clk;
> +};
> +
> +Then, to add the clock frequency to the device's migrated state, the vmstate
> +description is:
> +VMStateDescription my_device_vmstate = {
> +    .name = "my_device",
> +    .fields = (VMStateField[]) {
> +        VMSTATE_CLOCKIN(clk, MyDeviceState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +When adding a input clock support to an existing device, you must care about
> +migration compatibility. To this end, you can use the clock_init_frequency in
> +a pre_load function to setup a default value in case the source vm does not
> +migrate the frequency.

thanks
-- PMM
Damien Hedde Dec. 4, 2019, 12:11 p.m. UTC | #2
On 12/2/19 4:17 PM, Peter Maydell wrote:
> On Wed, 4 Sep 2019 at 13:56, Damien Hedde <damien.hedde@greensocs.com> wrote:
>>
>> Add the documentation about the clock inputs and outputs in devices.
>>
>> This is based on the original work of Frederic Konrad.
>>
>> Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
>> ---
>>  docs/devel/clock.txt | 246 +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 246 insertions(+)
>>  create mode 100644 docs/devel/clock.txt
> 
> Could you convert this to rst format, please?Yes.
> 
> 
> 
>> +Changing a clock output
>> +=======================
>> +
>> +A device can change its outputs using the clock_set_frequency function. It
>> +will trigger updates on every connected inputs.
> 
> "input"
> 
>> +
>> +For example, let's say that we have an output clock "clkout" and we have a
>> +pointer to it in the device state because we did the following in init phase:
>> +dev->clkout = qdev_init_clock_out(DEVICE(dev), "clkout");
>> +
>> +Then at any time (apart from the cases listed below), it is possible to
>> +change the clock value by doing:
>> +clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Ghz */
>> +This operation must be done while holding the qemu io lock.
>> +
>> +One can change clocks only when it is allowed to have side effects on other
>> +objects. In consequence, it is forbidden:
>> ++ during migration,
>> ++ and in the init phase of reset.
>> +
>> +Forwarding clocks
>> +=================
>> +
>> +Sometimes, one needs to forward, or inherit, a clock from another device.
>> +Typically, when doing device composition, a device might expose a sub-device's
>> +clock without interfering with it.
>> +The function qdev_pass_clock() can be used to achieve this behaviour. Note, that
> 
> "Note that"
> 
>> +it is possible to expose the clock under a different name. This works for both
>> +inputs or outputs.
> 
> "inputs and outputs"
> 
> 
>> +Migration
>> +=========
>> +
>> +Only the ClockIn object has a state. ClockOut is not concerned by migration.
> 
> "has any state".
> 
> "ClockOut has no state and does not need special handling for migration."
> 
>> +
>> +In case the frequency of in input clock is needed for a device's migration,
>> +this state must be migrated.
> 
> Are you trying to say that if an input clock is known to be a
> fixed frequency we don't need to migrate anything? I wonder
> if we need to worry about that or if we could/should just say that
> input clocks should always be migrated.

What I wanted to say is that there are indeed probably cases where
migrating the frequency is unnecessary. For example if we only use the
callback and never fetch the frequency outside it: if the frequency is
only used to compute something which is already saved/loaded during
migration.

But yes we could just do as you say. It's probably less confusing.

> 
>> The VMSTATE_CLOCKIN macro defines an entry to
>> +be added in a vmstate description.
>> +
>> +For example, if a device has a clock input and the device state looks like:
>> +MyDeviceState {
>> +    DeviceState parent_obj;
>> +    ClockIn *clk;
>> +};
>> +
>> +Then, to add the clock frequency to the device's migrated state, the vmstate
>> +description is:
>> +VMStateDescription my_device_vmstate = {
>> +    .name = "my_device",
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_CLOCKIN(clk, MyDeviceState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +When adding a input clock support to an existing device, you must care about
>> +migration compatibility. To this end, you can use the clock_init_frequency in
>> +a pre_load function to setup a default value in case the source vm does not
>> +migrate the frequency.
> 
> thanks
> -- PMM
>
diff mbox series

Patch

diff --git a/docs/devel/clock.txt b/docs/devel/clock.txt
new file mode 100644
index 0000000000..18f79922d0
--- /dev/null
+++ b/docs/devel/clock.txt
@@ -0,0 +1,246 @@ 
+
+What are clocks
+===============
+
+Clocks are objects representing input and output clocks of objects. They are
+QOM objects developed for the purpose of modeling the distribution of clocks in
+QEMU.
+
+This allows us to model the clock distribution of a platform and detect
+configuration errors in the clock tree such as badly configured PLL, clock
+source selection or disabled clock.
+
+The objects are ClockIn for the input and ClockOut for the output. The QOM
+names are respectively CLOCK_IN and CLOCK_OUT.
+
+CLOCK_IN and CLOCK_OUT are typically child of some device and created in a
+similar way as gpios. ClockIn and ClockOut of different devices can be
+connected together. It is possible to create a clock which is not related
+to a device; for example to model a clock source of a machine.
+
+Here is an example of devices with clocks:
+
+                             +-------------------+     +--------------------+
+                             |      Device B     |     |      Device C      |
+  +--------------------+     |           +-----+ |     | +-----+            |
+  |      Device A      |     |           |Clock|>>----->>|Clock|            |
+  |            +-----+ |     | +-----+   |Out 3| |     | |In  5|            |
+  |            |Clock|>>--+-->>|Clock|   +-----+ |     | +-----+            |
+  |            |Out 1| |  |  | |In 2 |   +-----+ |     | +-----+            |
+  |            +-----+ |  |  | +-----+   |Clock|>>----->>|Clock|            |
+  +--------------------+  |  |           |Out 4| |     | |In  6|            |
+                          |  |           +-----+ |     | +-----+            |
+                          |  +-------------------+     +--------------------+
+                          |
+                          |  +--------------------+
+                          |  |      Device D      |
+                          |  | +-----+            |
+                          +-->>|Clock|            |
+                             | |In  7|            |
+                             | +-----+            |
+                             +--------------------+
+
+Clocks are defined in include/hw/clock.h header and device related functions
+are defined in hw/qdev-clock.h header.
+
+The clock state
+===============
+
+The state of a clock is its frequency; it is stored as an integer representing
+it in Hertz. The special value of 0 is used to represent the clock being
+inactive or gated. The clocks do not model the signal itself (pin toggling)
+or other properties such as the duty cycle.
+
+Only the CLOCK_IN object keeps the value of a clock; this allows a device to
+fetch the current input frequency at any time. When an output is updated, the
+value is immediately propagated to all connected CLOCK_IN.
+
+Adding clocks to a device
+=========================
+
+Adding clocks to a device must be done during the init method of the Device
+instance.
+
+To add an input clock to a device, the function qdev_init_clock_in must be used.
+It takes the name, a callback, and an opaque parameter for the clock.
+Output is more simple, only the name is required. Typically:
+qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev);
+qdev_init_clock_out(DEVICE(dev), "clk_out");
+
+Both functions return the created ClockIn/ClockOut pointer, which should be saved
+in the device's state structure for further use.
+
+These objects will be automatically deleted by the QOM reference mechanism.
+
+Note that it is possible to create a static array describing clock inputs and
+outputs. The function qdev_init_clocks() must be called with the array as
+parameter to initialize the clocks: it has the same behaviour as calling the
+qdev_init_clock_in/out() for each clock in the array. To ease the array
+construction, some macros are defined in include/hw/qdev-clock.h.
+As an example, the following creates 2 clocks to a device: 1 input and 1
+output.
+
+/* device structure containing pointer to the clock objects */
+typedef struct MyDeviceState {
+    DeviceState parent_obj;
+    ClockIn *clk_in;
+    ClockOut *clk_out;
+} MyDeviceState;
+
+/*
+ * callback for the input clock (see "Callback on input clock change" section
+ * below for more information).
+ */
+static void clk_in_callback(void *opaque);
+
+/*
+ * static array describing clocks:
+ * + a clock input named "clk_in", whose pointer is stored in clk_in
+ *   field of a MyDeviceState structure with callback clk_in_callback.
+ * + a clock output named "clk_out" whose pointer is stored in clk_out
+ *   field of a MyDeviceState structure.
+ */
+static const ClockPortInitArray mydev_clocks = {
+    QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback),
+    QDEV_CLOCK_OUT(MyDeviceState, clk_out),
+    QDEV_CLOCK_END
+};
+
+/* device initialization function */
+static void mydev_init(Object *obj)
+{
+    /* cast to MyDeviceState */
+    MyDeviceState *mydev = MYDEVICE(obj);
+    /* create and fill the pointer fields in the MyDeviceState */
+    qdev_init_clocks(mydev, mydev_clocks);
+    [...]
+}
+
+Connecting two clocks together
+==============================
+
+Let's say we have 2 devices A and B. A has an output clock named "clk_out" and
+B has an input clock named "clk_in".
+
+The clocks are connected together using the function qdev_connect_clock:
+qdev_connect_clock(B, "clk_in", A, "clk_out", &error_abort);
+The device which has the input must be the first argument.
+
+It is possible to connect several input clocks to the same output. Every
+input callback will be called when the output changes.
+
+It is not possible to disconnect a clock or to change the clock connection
+after it is done.
+
+Unconnected input clocks
+========================
+
+A newly created input clock has a stored frequency value of 0. It means the
+clock will be considered as disabled until one sets a new frequency to the
+output clock it is connected to. If the clock remains unconnected it will
+always keep its initial value of 0.
+If this is not the wanted behaviour, clock_init_frequency should be called
+on the ClockIn object during device instance init.
+For example:
+clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, dev);
+clock_init_frequency(clk, 100 * 1000 * 1000); // default value is 100Mhz
+
+Using clock input frequency
+===========================
+
+A device can get the current frequency of an input using the
+clock_get_frequency(). It returns the last set frequency (or the init value).
+
+It is also possible to register a callback on input clock frequency changes.
+Here is an example:
+void clock_callback(void *opaque) {
+    MyDeviceState *s = (MyDeviceState *) opaque;
+    /*
+     * opaque may not be the device state pointer, but most probably it is.
+     * (It depends on what is given to the qdev_init_clock_in function)
+     */
+
+    /* do something with the new frequency */
+    fprintf(stdout, "device new frequency is %" PRIu64 "Hz\n",
+                    clock_get_frequency(dev->my_clk_input));
+}
+
+Changing a clock output
+=======================
+
+A device can change its outputs using the clock_set_frequency function. It
+will trigger updates on every connected inputs.
+
+For example, let's say that we have an output clock "clkout" and we have a
+pointer to it in the device state because we did the following in init phase:
+dev->clkout = qdev_init_clock_out(DEVICE(dev), "clkout");
+
+Then at any time (apart from the cases listed below), it is possible to
+change the clock value by doing:
+clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Ghz */
+This operation must be done while holding the qemu io lock.
+
+One can change clocks only when it is allowed to have side effects on other
+objects. In consequence, it is forbidden:
++ during migration,
++ and in the init phase of reset.
+
+Forwarding clocks
+=================
+
+Sometimes, one needs to forward, or inherit, a clock from another device.
+Typically, when doing device composition, a device might expose a sub-device's
+clock without interfering with it.
+The function qdev_pass_clock() can be used to achieve this behaviour. Note, that
+it is possible to expose the clock under a different name. This works for both
+inputs or outputs.
+
+For example, if device B is a child of device A, device_a_instance_init may
+do something like this:
+void device_a_instance_init(Object *obj)
+{
+    AState *A = DEVICE_A(obj);
+    BState *B;
+    /* create B object as child of A */
+    [...]
+    /* forward B's clock to A */
+    qdev_pass_clock(A, "b_clk", B, "clk");
+    /*
+     * Now A has a clock "b_clk" which forwards to
+     * the "clk" of its child B.
+     */
+}
+
+This function does not return any clock object. It is not possible to add
+a callback on a forwarded input clock: in the above example, only B can use
+the clock.
+
+Migration
+=========
+
+Only the ClockIn object has a state. ClockOut is not concerned by migration.
+
+In case the frequency of in input clock is needed for a device's migration,
+this state must be migrated. The VMSTATE_CLOCKIN macro defines an entry to
+be added in a vmstate description.
+
+For example, if a device has a clock input and the device state looks like:
+MyDeviceState {
+    DeviceState parent_obj;
+    ClockIn *clk;
+};
+
+Then, to add the clock frequency to the device's migrated state, the vmstate
+description is:
+VMStateDescription my_device_vmstate = {
+    .name = "my_device",
+    .fields = (VMStateField[]) {
+        VMSTATE_CLOCKIN(clk, MyDeviceState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+When adding a input clock support to an existing device, you must care about
+migration compatibility. To this end, you can use the clock_init_frequency in
+a pre_load function to setup a default value in case the source vm does not
+migrate the frequency.