Message ID | 20181002142443.30976-6-damien.hedde@greensocs.com |
---|---|
State | New |
Headers | show |
Series | Clock framework API. | expand |
On 10/2/18 4:24 PM, Damien Hedde 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 | 163 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 163 insertions(+) > create mode 100644 docs/devel/clock.txt > > diff --git a/docs/devel/clock.txt b/docs/devel/clock.txt > new file mode 100644 > index 0000000000..6dd8abdee6 > --- /dev/null > +++ b/docs/devel/clock.txt > @@ -0,0 +1,163 @@ > + > +What are device's clocks > +======================== > + > +Clocks are ports representing input and output clocks of a device. 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 CLOCK_IN for the input and CLOCK_OUT for the output. A simple ASCII diagram would help to make this clearer. > + > +The clock value: ClockState > +=========================== > + > +The ClockState is the structure carried by the CLOCK_OUT and CLOCK_IN objects. This is only true for ClockIn, right? > +It contains one integer field representing the frequency of the clock in Hertz. unsigned > + > +It only simulates the clock by transmitting the frequency value and > +doesn't model the signal itself such as pin toggle or duty cycle. > +The special value 0 as a frequency is legal and represent the clock being > +inactive or gated. OK. > + > +Adding clocks to a device > +========================= > + > +Adding clocks to a device must be done during the init phase of the Device > +object. > + > +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 CLOCK_IN/OUT pointer, which should be saved ClockIn/ClockOut > +in the device's state structure. > + > +Theses objects will be automatically deleted by the qom reference mechanism. QOM > + > +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 > +parameters to initialize the clocks: it has the same behaviour as calling the > +qdev_init_clock/out for each clock in the array. > + > +Unconnected input clocks > +======================== > + > +Unconnected input clocks have a default frequency value of 0. It means the > +clock will be considered as disabled. If this is not the wanted behaviour, > +clock_init_frequency should be called on the ClockIn object during device init. > +For example: > +clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, dev); > +clock_init_frequency(clk, 100 * 1000 * 1000); // init value is 100Mhz > + > +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 */ > + 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 returns any clock object. It is not possible to add > +a callback on a forwarded input clock. > + > +Connecting two clocks together > +============================== > + > +Let's say we have 2 devices A and B. A has an output clock named "clkout" and B > +has an input clock named "clkin". Maybe "clk_in" "clk_out" to avoid confusion with ClkIn and ClkOut. > + > +The clocks are connected together using the function qdev_connect_clock: > +qdev_connect_clock(B, "clkin", A, "clkout", &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. > + > +Changing a clock output > +======================= > + > +A device can change its outputs using the clock_set function. It will trigger > +updates on any 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, it is possible to change the clock value by doing: > +clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Mhz */ 1GHz > + > +Callback on input clock change > +============================== > + > +Here is an example of an input callback: > +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)); Yes. > +} > + > +The state argument needs only to be copied if the device needs to use the value > +later: the state pointer argument of the pointer will not be valid anymore > +after the end of the function. > + > +Migration > +========= > + > +Only the CLOCK_IN object has a state. CLOCK_OUT frequency should not be set ClkIn ClkOut > +in migration post_load. > + > +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. > Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Hi Damien, On 02/10/2018 16:24, Damien Hedde 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 | 163 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 163 insertions(+) > create mode 100644 docs/devel/clock.txt > > diff --git a/docs/devel/clock.txt b/docs/devel/clock.txt > new file mode 100644 > index 0000000000..6dd8abdee6 > --- /dev/null > +++ b/docs/devel/clock.txt > @@ -0,0 +1,163 @@ > + > +What are device's clocks > +======================== > + > +Clocks are ports representing input and output clocks of a device. 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 CLOCK_IN for the input and CLOCK_OUT for the output. > + > +The clock value: ClockState > +=========================== > + > +The ClockState is the structure carried by the CLOCK_OUT and CLOCK_IN objects. > +It contains one integer field representing the frequency of the clock in Hertz. > + > +It only simulates the clock by transmitting the frequency value and > +doesn't model the signal itself such as pin toggle or duty cycle. > +The special value 0 as a frequency is legal and represent the clock being > +inactive or gated. > + > +Adding clocks to a device > +========================= > + > +Adding clocks to a device must be done during the init phase of the Device > +object. > + > +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 CLOCK_IN/OUT pointer, which should be saved > +in the device's state structure. > + > +Theses 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 > +parameters to initialize the clocks: it has the same behaviour as calling the > +qdev_init_clock/out for each clock in the array. Can you add a simple example here? > + > +Unconnected input clocks > +======================== > + > +Unconnected input clocks have a default frequency value of 0. It means the > +clock will be considered as disabled. If this is not the wanted behaviour, > +clock_init_frequency should be called on the ClockIn object during device init. > +For example: > +clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, dev); > +clock_init_frequency(clk, 100 * 1000 * 1000); // init value is 100Mhz > + > +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 */ > + 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 returns any clock object. It is not possible to add > +a callback on a forwarded input clock. > + > +Connecting two clocks together > +============================== > + > +Let's say we have 2 devices A and B. A has an output clock named "clkout" and B > +has an input clock named "clkin". > + > +The clocks are connected together using the function qdev_connect_clock: > +qdev_connect_clock(B, "clkin", A, "clkout", &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. > + > +Changing a clock output > +======================= > + > +A device can change its outputs using the clock_set function. It will trigger > +updates on any 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, it is possible to change the clock value by doing: > +clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Mhz */ > + > +Callback on input clock change > +============================== > + > +Here is an example of an input callback: > +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)); > +} > + > +The state argument needs only to be copied if the device needs to use the value > +later: the state pointer argument of the pointer will not be valid anymore > +after the end of the function. > + > +Migration > +========= > + > +Only the CLOCK_IN object has a state. CLOCK_OUT frequency should not be set > +in migration post_load. > + > +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. >
diff --git a/docs/devel/clock.txt b/docs/devel/clock.txt new file mode 100644 index 0000000000..6dd8abdee6 --- /dev/null +++ b/docs/devel/clock.txt @@ -0,0 +1,163 @@ + +What are device's clocks +======================== + +Clocks are ports representing input and output clocks of a device. 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 CLOCK_IN for the input and CLOCK_OUT for the output. + +The clock value: ClockState +=========================== + +The ClockState is the structure carried by the CLOCK_OUT and CLOCK_IN objects. +It contains one integer field representing the frequency of the clock in Hertz. + +It only simulates the clock by transmitting the frequency value and +doesn't model the signal itself such as pin toggle or duty cycle. +The special value 0 as a frequency is legal and represent the clock being +inactive or gated. + +Adding clocks to a device +========================= + +Adding clocks to a device must be done during the init phase of the Device +object. + +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 CLOCK_IN/OUT pointer, which should be saved +in the device's state structure. + +Theses 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 +parameters to initialize the clocks: it has the same behaviour as calling the +qdev_init_clock/out for each clock in the array. + +Unconnected input clocks +======================== + +Unconnected input clocks have a default frequency value of 0. It means the +clock will be considered as disabled. If this is not the wanted behaviour, +clock_init_frequency should be called on the ClockIn object during device init. +For example: +clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, dev); +clock_init_frequency(clk, 100 * 1000 * 1000); // init value is 100Mhz + +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 */ + 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 returns any clock object. It is not possible to add +a callback on a forwarded input clock. + +Connecting two clocks together +============================== + +Let's say we have 2 devices A and B. A has an output clock named "clkout" and B +has an input clock named "clkin". + +The clocks are connected together using the function qdev_connect_clock: +qdev_connect_clock(B, "clkin", A, "clkout", &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. + +Changing a clock output +======================= + +A device can change its outputs using the clock_set function. It will trigger +updates on any 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, it is possible to change the clock value by doing: +clock_set_frequency(dev->clkout, 1000 * 1000 * 1000); /* 1Mhz */ + +Callback on input clock change +============================== + +Here is an example of an input callback: +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)); +} + +The state argument needs only to be copied if the device needs to use the value +later: the state pointer argument of the pointer will not be valid anymore +after the end of the function. + +Migration +========= + +Only the CLOCK_IN object has a state. CLOCK_OUT frequency should not be set +in migration post_load. + +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.
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 | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 docs/devel/clock.txt