diff mbox

[v1,1/2] qdev-monitor.c: Register reset function if the device has one

Message ID 4744c26fdfd911c44b58a9b6e1d0effc6cb39594.1455739133.git.alistair.francis@xilinx.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alistair Francis Feb. 17, 2016, 9:04 p.m. UTC
If the device being added when running qdev_device_add() has
a reset function, register it so that it can be called.

Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
---

 qdev-monitor.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Markus Armbruster Feb. 18, 2016, 9:56 a.m. UTC | #1
Alistair Francis <alistair.francis@xilinx.com> writes:

> If the device being added when running qdev_device_add() has
> a reset function, register it so that it can be called.
>
> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
> ---
>
>  qdev-monitor.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/qdev-monitor.c b/qdev-monitor.c
> index 81e3ff3..0a99d01 100644
> --- a/qdev-monitor.c
> +++ b/qdev-monitor.c
> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>  
>      if (bus) {
>          qdev_set_parent_bus(dev, bus);
> +    } else if (dc->reset) {
> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>      }
>  
>      id = qemu_opts_id(opts);

This looks wrong to me.

You stuff all the device reset methods into the global reset_handlers
list, where they get called in some semi-random order.  This breaks when
there are reset order dependencies between devices, e.g. between a
device and the bus it plugs into.

Propagating the reset signal to all the devices is a qdev problem.
Copying Andreas for further insight.
Alistair Francis Feb. 18, 2016, 6:47 p.m. UTC | #2
On Thu, Feb 18, 2016 at 1:56 AM, Markus Armbruster <armbru@redhat.com> wrote:
> Alistair Francis <alistair.francis@xilinx.com> writes:
>
>> If the device being added when running qdev_device_add() has
>> a reset function, register it so that it can be called.
>>
>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>> ---
>>
>>  qdev-monitor.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>> index 81e3ff3..0a99d01 100644
>> --- a/qdev-monitor.c
>> +++ b/qdev-monitor.c
>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>
>>      if (bus) {
>>          qdev_set_parent_bus(dev, bus);
>> +    } else if (dc->reset) {
>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>      }
>>
>>      id = qemu_opts_id(opts);
>
> This looks wrong to me.
>
> You stuff all the device reset methods into the global reset_handlers
> list, where they get called in some semi-random order.  This breaks when
> there are reset order dependencies between devices, e.g. between a
> device and the bus it plugs into.

So I'm not a expert on this, but from what I see this will also be
added near the end of the list (before the rom_resets though) and
doesn't seem to be a problem. Do you have any other ideas how the
reset function could be registered?

Thanks,

Alistair

>
> Propagating the reset signal to all the devices is a qdev problem.
> Copying Andreas for further insight.
>
Paolo Bonzini Feb. 18, 2016, 9:47 p.m. UTC | #3
On 18/02/2016 10:56, Markus Armbruster wrote:
> Alistair Francis <alistair.francis@xilinx.com> writes:
> 
>> If the device being added when running qdev_device_add() has
>> a reset function, register it so that it can be called.
>>
>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>> ---
>>
>>  qdev-monitor.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>> index 81e3ff3..0a99d01 100644
>> --- a/qdev-monitor.c
>> +++ b/qdev-monitor.c
>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>  
>>      if (bus) {
>>          qdev_set_parent_bus(dev, bus);
>> +    } else if (dc->reset) {
>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>      }
>>  
>>      id = qemu_opts_id(opts);
> 
> This looks wrong to me.
> 
> You stuff all the device reset methods into the global reset_handlers
> list, where they get called in some semi-random order.  This breaks when
> there are reset order dependencies between devices, e.g. between a
> device and the bus it plugs into.

There is no bus here, see the "if" above the one that's being added.

However, what devices have done so far is to register/unregister the
reset in the realize/unrealize methods, and I suggest doing the same.

If you really want to add the magic qemu_register_reset, you should at
least do one of the following:

* add a matching unregister (no idea where)

* assert that the device is not hot-unpluggable, otherwise hot-unplug
would leave a dangling pointer.

Paolo

> Propagating the reset signal to all the devices is a qdev problem.
> Copying Andreas for further insight.
Peter Crosthwaite Feb. 18, 2016, 11:07 p.m. UTC | #4
On Thu, Feb 18, 2016 at 1:47 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
>
> On 18/02/2016 10:56, Markus Armbruster wrote:
>> Alistair Francis <alistair.francis@xilinx.com> writes:
>>
>>> If the device being added when running qdev_device_add() has
>>> a reset function, register it so that it can be called.
>>>
>>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>>> ---
>>>
>>>  qdev-monitor.c | 2 ++
>>>  1 file changed, 2 insertions(+)
>>>
>>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>>> index 81e3ff3..0a99d01 100644
>>> --- a/qdev-monitor.c
>>> +++ b/qdev-monitor.c
>>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>>
>>>      if (bus) {
>>>          qdev_set_parent_bus(dev, bus);
>>> +    } else if (dc->reset) {
>>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>>      }
>>>
>>>      id = qemu_opts_id(opts);
>>
>> This looks wrong to me.
>>
>> You stuff all the device reset methods into the global reset_handlers
>> list, where they get called in some semi-random order.  This breaks when
>> there are reset order dependencies between devices, e.g. between a
>> device and the bus it plugs into.
>
> There is no bus here, see the "if" above the one that's being added.
>
> However, what devices have done so far is to register/unregister the
> reset in the realize/unrealize methods, and I suggest doing the same.
>

Does this assume the device itself knows whether it is bus-connected
or not? This way has the advantage of catchall-ing devices that have
no bus connected and the device may or may not know whether it is
bus-connected (nor should it need to know). Probably doesn't have in
tree precedent yet, but I thought we wanted to move away from
qdev/qbus managing the device-tree. So ideally, the new else should
become unconditional long term once we debusify (and properly QOMify)
the reset tree (and the if goes away).

> If you really want to add the magic qemu_register_reset, you should at
> least do one of the following:
>
> * add a matching unregister (no idea where)
>

You could add a boolean flag to DeviceState that is set by this
registration. It can then be checked at unrealize to remove reset
handler.

Regards,
Peter

> * assert that the device is not hot-unpluggable, otherwise hot-unplug
> would leave a dangling pointer.
>
> Paolo
>
>> Propagating the reset signal to all the devices is a qdev problem.
>> Copying Andreas for further insight.
Alistair Francis Feb. 19, 2016, 12:02 a.m. UTC | #5
On Thu, Feb 18, 2016 at 3:07 PM, Peter Crosthwaite
<crosthwaitepeter@gmail.com> wrote:
> On Thu, Feb 18, 2016 at 1:47 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>
>>
>> On 18/02/2016 10:56, Markus Armbruster wrote:
>>> Alistair Francis <alistair.francis@xilinx.com> writes:
>>>
>>>> If the device being added when running qdev_device_add() has
>>>> a reset function, register it so that it can be called.
>>>>
>>>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>>>> ---
>>>>
>>>>  qdev-monitor.c | 2 ++
>>>>  1 file changed, 2 insertions(+)
>>>>
>>>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>>>> index 81e3ff3..0a99d01 100644
>>>> --- a/qdev-monitor.c
>>>> +++ b/qdev-monitor.c
>>>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>>>
>>>>      if (bus) {
>>>>          qdev_set_parent_bus(dev, bus);
>>>> +    } else if (dc->reset) {
>>>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>>>      }
>>>>
>>>>      id = qemu_opts_id(opts);
>>>
>>> This looks wrong to me.
>>>
>>> You stuff all the device reset methods into the global reset_handlers
>>> list, where they get called in some semi-random order.  This breaks when
>>> there are reset order dependencies between devices, e.g. between a
>>> device and the bus it plugs into.
>>
>> There is no bus here, see the "if" above the one that's being added.
>>
>> However, what devices have done so far is to register/unregister the
>> reset in the realize/unrealize methods, and I suggest doing the same.

Ok, I am happy to do it that way. It just seemed dodgy to me
registering the reset in the realise.

This also seemed like a feature worth having, as I thought this would
come up again in the future.

>>
>
> Does this assume the device itself knows whether it is bus-connected
> or not? This way has the advantage of catchall-ing devices that have
> no bus connected and the device may or may not know whether it is
> bus-connected (nor should it need to know). Probably doesn't have in
> tree precedent yet, but I thought we wanted to move away from
> qdev/qbus managing the device-tree. So ideally, the new else should
> become unconditional long term once we debusify (and properly QOMify)
> the reset tree (and the if goes away).

That was my general thinking as well.

Thanks,

Alistair

>
>> If you really want to add the magic qemu_register_reset, you should at
>> least do one of the following:
>>
>> * add a matching unregister (no idea where)
>>
>
> You could add a boolean flag to DeviceState that is set by this
> registration. It can then be checked at unrealize to remove reset
> handler.
>
> Regards,
> Peter
>
>> * assert that the device is not hot-unpluggable, otherwise hot-unplug
>> would leave a dangling pointer.
>>
>> Paolo
>>
>>> Propagating the reset signal to all the devices is a qdev problem.
>>> Copying Andreas for further insight.
>
Paolo Bonzini Feb. 19, 2016, 9:33 a.m. UTC | #6
On 19/02/2016 00:07, Peter Crosthwaite wrote:
> On Thu, Feb 18, 2016 at 1:47 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>
>>
>> On 18/02/2016 10:56, Markus Armbruster wrote:
>>> Alistair Francis <alistair.francis@xilinx.com> writes:
>>>
>>>> If the device being added when running qdev_device_add() has
>>>> a reset function, register it so that it can be called.
>>>>
>>>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>>>> ---
>>>>
>>>>  qdev-monitor.c | 2 ++
>>>>  1 file changed, 2 insertions(+)
>>>>
>>>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>>>> index 81e3ff3..0a99d01 100644
>>>> --- a/qdev-monitor.c
>>>> +++ b/qdev-monitor.c
>>>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>>>
>>>>      if (bus) {
>>>>          qdev_set_parent_bus(dev, bus);
>>>> +    } else if (dc->reset) {
>>>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>>>      }
>>>>
>>>>      id = qemu_opts_id(opts);
>>>
>>> This looks wrong to me.
>>>
>>> You stuff all the device reset methods into the global reset_handlers
>>> list, where they get called in some semi-random order.  This breaks when
>>> there are reset order dependencies between devices, e.g. between a
>>> device and the bus it plugs into.
>>
>> There is no bus here, see the "if" above the one that's being added.
>>
>> However, what devices have done so far is to register/unregister the
>> reset in the realize/unrealize methods, and I suggest doing the same.
> 
> Does this assume the device itself knows whether it is bus-connected
> or not? This way has the advantage of catchall-ing devices that have
> no bus connected and the device may or may not know whether it is
> bus-connected (nor should it need to know).

A device almost definitely needs to know if it is bus connected.  More
likely than not, a busless device inherits from DeviceState while a
device with a bus inherits from SCSIDevice, PCIDevice, I2CSlave, etc.

> Probably doesn't have in
> tree precedent yet, but I thought we wanted to move away from
> qdev/qbus managing the device-tree. So ideally, the new else should
> become unconditional long term once we debusify (and properly QOMify)
> the reset tree (and the if goes away).

Any abstraction we have in QEMU should have at least a parallel (though
it need not be the same) in real hardware.  Reset signals _do_ propagate
along buses, or at least along some buses, so "debusifying" reset seems
like a counterproductive goal to me.

For busless devices, I thought the idea was just to have the QOM parent
(container) propagate the realize/reset/unrealize signals in the right
order.  Unfortunately reality is not quite as simple and indeed here
however you have a busless device that:

- doesn't have a container (the container is just /machine/unattached or
similar).

- triggers a reset for something else that is not contained in it (the
CPU) and even some DMA.

>> If you really want to add the magic qemu_register_reset, you should at
>> least do one of the following:
>>
>> * add a matching unregister (no idea where)
> 
> You could add a boolean flag to DeviceState that is set by this
> registration. It can then be checked at unrealize to remove reset
> handler.

Yeah, I guess that would work.  A few changes:

- you register the callback unconditionally for all busless devices,
using qdev_reset_all_fn instead of directly dc->reset

- you do it after the "realized" property has been set successfully.
Otherwise, a failed -device or device_add will also leave a dangling
callback.

- add a comment that this is because the callback is registered because
this is a busless _and_ container-less device

Paolo
Markus Armbruster Feb. 19, 2016, 9:58 a.m. UTC | #7
Paolo Bonzini <pbonzini@redhat.com> writes:

> On 18/02/2016 10:56, Markus Armbruster wrote:
>> Alistair Francis <alistair.francis@xilinx.com> writes:
>> 
>>> If the device being added when running qdev_device_add() has
>>> a reset function, register it so that it can be called.
>>>
>>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>>> ---
>>>
>>>  qdev-monitor.c | 2 ++
>>>  1 file changed, 2 insertions(+)
>>>
>>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>>> index 81e3ff3..0a99d01 100644
>>> --- a/qdev-monitor.c
>>> +++ b/qdev-monitor.c
>>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>>  
>>>      if (bus) {
>>>          qdev_set_parent_bus(dev, bus);
>>> +    } else if (dc->reset) {
>>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>>      }
>>>  
>>>      id = qemu_opts_id(opts);
>> 
>> This looks wrong to me.
>> 
>> You stuff all the device reset methods into the global reset_handlers
>> list, where they get called in some semi-random order.  This breaks when
>> there are reset order dependencies between devices, e.g. between a
>> device and the bus it plugs into.
>
> There is no bus here, see the "if" above the one that's being added.
>
> However, what devices have done so far is to register/unregister the
> reset in the realize/unrealize methods, and I suggest doing the same.

Shows that our support for bus-less devices is still in its infancy.

For me, a device has a number of external connectors that need to be
wired up.  A qdev bus is merely a standardized package of such
connectors.  For historical reasons, buses are all qdev has, with a
special sysbus for everything that cannot be shoehorned into a single
bus.  To work with individual connectors, you have to drop into C
(ignoring the weird "platform bus" sysbus thing Alex added).  Support
for doing that at configuration rather than code level would be nice.

[...]
Peter Maydell Feb. 19, 2016, 10:55 a.m. UTC | #8
On 19 February 2016 at 09:33, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Any abstraction we have in QEMU should have at least a parallel (though
> it need not be the same) in real hardware.  Reset signals _do_ propagate
> along buses, or at least along some buses, so "debusifying" reset seems
> like a counterproductive goal to me.

Reset for some buses propagates along buses, but not in all
cases. In any case our current "reset" semantics are "power on
reset", not any kind of driven-by-hardware-reset-lines reset.

thanks
-- PMM
Andreas Färber Feb. 19, 2016, 5:15 p.m. UTC | #9
Am 18.02.2016 um 10:56 schrieb Markus Armbruster:
> Alistair Francis <alistair.francis@xilinx.com> writes:
> 
>> If the device being added when running qdev_device_add() has
>> a reset function, register it so that it can be called.
>>
>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>> ---
>>
>>  qdev-monitor.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>> index 81e3ff3..0a99d01 100644
>> --- a/qdev-monitor.c
>> +++ b/qdev-monitor.c
>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>  
>>      if (bus) {
>>          qdev_set_parent_bus(dev, bus);
>> +    } else if (dc->reset) {
>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>      }
>>  
>>      id = qemu_opts_id(opts);
> 
> This looks wrong to me.
> 
> You stuff all the device reset methods into the global reset_handlers
> list, where they get called in some semi-random order.  This breaks when
> there are reset order dependencies between devices, e.g. between a
> device and the bus it plugs into.
> 
> Propagating the reset signal to all the devices is a qdev problem.
> Copying Andreas for further insight.

We had a similar discussion for s390x, and I had started a big reset
refactoring, but we agreed to go for a stop-gap solution for 2.5. The
recently posted hw/core/bus.c refactoring originated from that branch.

The overall idea was that for buses reset propagates along buses (so
yes, NACK to this patch), but where no bus exists it shall propagate to
QOM children, too.

So Alistair, if you have a device that needs a reset while not sitting
on a bus, please register the register hook in your device's realize
hook for now.

Regards,
Andreas
Paolo Bonzini Feb. 19, 2016, 5:17 p.m. UTC | #10
On 19/02/2016 11:55, Peter Maydell wrote:
>> Any abstraction we have in QEMU should have at least a parallel (though
>> > it need not be the same) in real hardware.  Reset signals _do_ propagate
>> > along buses, or at least along some buses, so "debusifying" reset seems
>> > like a counterproductive goal to me.
> Reset for some buses propagates along buses, but not in all
> cases.

Agreed.  But still this doesn't change the fact that "debusifying" reset
is a non-goal.

> In any case our current "reset" semantics are "power on
> reset", not any kind of driven-by-hardware-reset-lines reset.

It depends.  There are several cases (PCI, SCSI) where qdev_reset_all is
used from within the code in order to provide hardware reset semantics.

Paolo
Alistair Francis Feb. 19, 2016, 6:53 p.m. UTC | #11
On Fri, Feb 19, 2016 at 9:15 AM, Andreas Färber <afaerber@suse.de> wrote:
> Am 18.02.2016 um 10:56 schrieb Markus Armbruster:
>> Alistair Francis <alistair.francis@xilinx.com> writes:
>>
>>> If the device being added when running qdev_device_add() has
>>> a reset function, register it so that it can be called.
>>>
>>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>>> ---
>>>
>>>  qdev-monitor.c | 2 ++
>>>  1 file changed, 2 insertions(+)
>>>
>>> diff --git a/qdev-monitor.c b/qdev-monitor.c
>>> index 81e3ff3..0a99d01 100644
>>> --- a/qdev-monitor.c
>>> +++ b/qdev-monitor.c
>>> @@ -561,6 +561,8 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>>
>>>      if (bus) {
>>>          qdev_set_parent_bus(dev, bus);
>>> +    } else if (dc->reset) {
>>> +        qemu_register_reset((void (*)(void *))dc->reset, dev);
>>>      }
>>>
>>>      id = qemu_opts_id(opts);
>>
>> This looks wrong to me.
>>
>> You stuff all the device reset methods into the global reset_handlers
>> list, where they get called in some semi-random order.  This breaks when
>> there are reset order dependencies between devices, e.g. between a
>> device and the bus it plugs into.
>>
>> Propagating the reset signal to all the devices is a qdev problem.
>> Copying Andreas for further insight.
>
> We had a similar discussion for s390x, and I had started a big reset
> refactoring, but we agreed to go for a stop-gap solution for 2.5. The
> recently posted hw/core/bus.c refactoring originated from that branch.
>
> The overall idea was that for buses reset propagates along buses (so
> yes, NACK to this patch), but where no bus exists it shall propagate to
> QOM children, too.
>
> So Alistair, if you have a device that needs a reset while not sitting
> on a bus, please register the register hook in your device's realize
> hook for now.

Ok, that is fair. I have moved the reset register/unregister to the
realise/unrealise functions in V2.

Thanks,

Alistair

>
> Regards,
> Andreas
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg)
>
diff mbox

Patch

diff --git a/qdev-monitor.c b/qdev-monitor.c
index 81e3ff3..0a99d01 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -561,6 +561,8 @@  DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
 
     if (bus) {
         qdev_set_parent_bus(dev, bus);
+    } else if (dc->reset) {
+        qemu_register_reset((void (*)(void *))dc->reset, dev);
     }
 
     id = qemu_opts_id(opts);