[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path |
Date: |
Sun, 4 Sep 2011 09:27:46 +0000 |
On Sat, Sep 3, 2011 at 9:41 PM, Anthony Liguori <address@hidden> wrote:
> On 09/03/2011 04:10 PM, Blue Swirl wrote:
>>
>> On Sat, Sep 3, 2011 at 8:07 PM, Anthony Liguori<address@hidden>
>> wrote:
>>>
>>> On 09/01/2011 12:58 AM, Avi Kivity wrote:
>>>>
>>>> On 08/31/2011 07:59 PM, Blue Swirl wrote:
>>>>>
>>>>>>
>>>>>> That makes it impossible to migrate level-triggered irq lines. Or at
>>>>>
>>>>> least,
>>>>>>
>>>>>> the receiver has to remember the state, instead of (or in addition
>>>>>
>>>>> to) the
>>>>>>
>>>>>> sender.
>>>>>
>>>>> Both ends probably need to remember the state. That should work
>>>>> without any multiphase restores and transient suppressors.
>>>>
>>>> State should always correspond to real hardware state - a flip flop or
>>>> capacitor. Input is not state, it is input.
>>>>
>>>>> It might be also possible to introduce stateful signal lines which
>>>>> save and restore their state, then the receiving end could check what
>>>>> is the current level. However, if you consider that the devices may be
>>>>> restored in random order, if the IRQ line device happens to be
>>>>> restored later, the receiver would still get wrong information. Adding
>>>>> priorities could solve this, but I think stateless IRQs are the only
>>>>> sane way.
>>>>
>>>> I agree that irqs should be stateless, since they don't have any memory
>>>> associated.
>>>
>>> In Real Life, you can tie a single bit multiple registers together with
>>> boolean logic to form an output pin. This is essentially computed state.
>>> If we wanted to model a stateless pin, we would need to do something
>>> like:
>>>
>>> struct Serial {
>>> uint8_t thr;
>>> uint8_t lsr;
>>> };
>>>
>>> static bool serial_get_irq(Serial *s) {
>>> return (s->thr& THRE) | (s->lsr& LSRE);
>>> }
>>>
>>> static void serial_write(Serial *s, uint64_t addr, uint8_t value)
>>> {
>>> switch (addr) {
>>> case THR:
>>> bool old_irq = serial_get_irq(s);
>>> s->thr = value;
>>> if (!old_irq&& serial_get_irq(s)) {
>>> notify_edge_change(s);
>>> }
>>> ...
>>> }
>>>
>>> static void serial_init(Serial *s)
>>> {
>>> register_pin(s, serial_get_irq);
>>> }
>>>
>>> Obviously, this is pretty sucky. This is what we do today but we don't
>>> have
>>> a way to query irq value which is wrong. You could fix that by adding
>>> the
>>> get function but that's not terribly fun. A better way:
>>>
>>> struct Serial {
>>> Pin irq;
>>> uint8_t thr;
>>> uint8_t lsr;
>>> };
>>>
>>> static void serial_update_irq(Serial *s)
>>> {
>>> pin_set_level(&s->irq, (s->thr& THRE) | (s->lsr& LSRE));
>>> }
>>>
>>> static void serial_write(Serial *s) {
>>> switch (addr) {
>>> case THR:
>>> s->thr = value;
>>> serial_update_irq(s);
>>> ...
>>> }
>>>
>>> This results in much nicer code. The edge handling can be done in
>>> generic
>>> code which will make things more robust overall.
>>
>> I'm sorry but I don't see a huge difference, could you elaborate?
>
> The main difference is whether the Pin is capable of determine if there was
> a level change on its own. It can only do this is if knows the current
> level which implies that its holding state.
>
>>
>> Maybe if the internal state of Pin is magically shared between the
>> endpoint devices (like typedef bool *Pin) and the devices somehow
>> still save Pin state as part of their own despite the duplication,
>
> I'm somewhat confused by what you mean here.
Pretty similar to what you propose below except the magical sharing.
> If you have two devices that have a connection, one has an output pin and
> one has an input pin. This would look like this:
>
> struct Serial {
> Pin irq; // output pin
> };
>
> struct PIIX3 {
> Pin *in[16]; // input pins
> };
>
> As part of connecting devices, you'd basically do:
>
> PIIX3 piix3;
> Serial serial;
>
> piix3.in[4] = &serial.irq;
>
> serial.irq setting it pin level doesn't do anything to piix3. piix3 has to
> explicitly read the pin state for its behavior to influence anything.
>
> Here's the flow with taking migration into account:
>
> 1) PIIX3 maintains some type of state, performs action (A) whenever in[3]
> changes its state based on an edge change notifier.
>
> 2) During migration, PIIX3 has its state saved as does Serial. Pin is part
> of Serial so it also has its state saved.
>
> 3) During restore, PIIX3 has its state restored, as does Serial, and Pin.
> Action (A) is not invoked because notifiers are not fired when a device is
> not realized. Restore happens before a device is realized.
>
> So the scenario you're concerned about doesn't happen and it doesn't require
> anything funky.
OK, this should work.
>> this could work. Restoring Pins first and then devices is a sort of
>> priority scheme.
>
> There is no priority. But devices have an explicit realize event and in
> general, shouldn't react to other devices until realize happens. You need
> this behavior to support construction properly.
>
> Regards,
>
> Anthony Liguori
>
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Anthony Liguori, 2011/09/03
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Blue Swirl, 2011/09/03
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Edgar E. Iglesias, 2011/09/05
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Edgar E. Iglesias, 2011/09/05
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Avi Kivity, 2011/09/05
- Re: [Qemu-devel] [PATCH] pc: Clean up PIC-to-APIC IRQ path, Edgar E. Iglesias, 2011/09/05