diff mbox series

[v9,2/7] hw/intc/i8259: Implement legacy LTIM Edge/Level Bank Select

Message ID 3f09b2dd109d19851d786047ad5c2ff459c90cd7.1678188711.git.balaton@eik.bme.hu
State New
Headers show
Series Pegasos2 fixes and audio output support | expand

Commit Message

BALATON Zoltan March 7, 2023, 11:42 a.m. UTC
From: David Woodhouse <dwmw2@infradead.org>

Back in the mists of time, before EISA came along and required per-pin
level control in the ELCR register, the i8259 had a single chip-wide
level-mode control in bit 3 of ICW1.

Even in the PIIX3 datasheet from 1996 this is documented as 'This bit is
disabled', but apparently MorphOS is using it in the version of the
i8259 which is in the Pegasos2 board as part of the VT8231 chipset.

It's easy enough to implement, and I think it's harmless enough to do so
unconditionally.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
[balaton: updated commit message as asked by author]
Tested-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/intc/i8259.c                 | 10 ++++------
 hw/intc/i8259_common.c          | 24 +++++++++++++++++++++++-
 include/hw/isa/i8259_internal.h |  1 +
 3 files changed, 28 insertions(+), 7 deletions(-)

Comments

Daniel Henrique Barboza March 7, 2023, 1:36 p.m. UTC | #1
On 3/7/23 08:42, BALATON Zoltan wrote:
> From: David Woodhouse <dwmw2@infradead.org>
> 
> Back in the mists of time, before EISA came along and required per-pin
> level control in the ELCR register, the i8259 had a single chip-wide
> level-mode control in bit 3 of ICW1.
> 
> Even in the PIIX3 datasheet from 1996 this is documented as 'This bit is
> disabled', but apparently MorphOS is using it in the version of the
> i8259 which is in the Pegasos2 board as part of the VT8231 chipset.
> 
> It's easy enough to implement, and I think it's harmless enough to do so
> unconditionally.
> 
> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
> [balaton: updated commit message as asked by author]
> Tested-by: BALATON Zoltan <balaton@eik.bme.hu>
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> ---
>   hw/intc/i8259.c                 | 10 ++++------
>   hw/intc/i8259_common.c          | 24 +++++++++++++++++++++++-
>   include/hw/isa/i8259_internal.h |  1 +
>   3 files changed, 28 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
> index 17910f3bcb..bbae2d87f4 100644
> --- a/hw/intc/i8259.c
> +++ b/hw/intc/i8259.c
> @@ -133,7 +133,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
>       }
>   #endif
>   
> -    if (s->elcr & mask) {
> +    if (s->ltim || (s->elcr & mask)) {
>           /* level triggered */
>           if (level) {
>               s->irr |= mask;
> @@ -167,7 +167,7 @@ static void pic_intack(PICCommonState *s, int irq)
>           s->isr |= (1 << irq);
>       }
>       /* We don't clear a level sensitive interrupt here */
> -    if (!(s->elcr & (1 << irq))) {
> +    if (!s->ltim && !(s->elcr & (1 << irq))) {
>           s->irr &= ~(1 << irq);
>       }
>       pic_update_irq(s);
> @@ -224,6 +224,7 @@ static void pic_reset(DeviceState *dev)
>       PICCommonState *s = PIC_COMMON(dev);
>   
>       s->elcr = 0;
> +    s->ltim = 0;
>       pic_init_reset(s);
>   }
>   
> @@ -243,10 +244,7 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
>               s->init_state = 1;
>               s->init4 = val & 1;
>               s->single_mode = val & 2;
> -            if (val & 0x08) {
> -                qemu_log_mask(LOG_UNIMP,
> -                              "i8259: level sensitive irq not supported\n");
> -            }
> +            s->ltim = val & 8;
>           } else if (val & 0x08) {
>               if (val & 0x04) {
>                   s->poll = 1;
> diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
> index af2e4a2241..c931dc2d07 100644
> --- a/hw/intc/i8259_common.c
> +++ b/hw/intc/i8259_common.c
> @@ -51,7 +51,7 @@ void pic_reset_common(PICCommonState *s)
>       s->special_fully_nested_mode = 0;
>       s->init4 = 0;
>       s->single_mode = 0;
> -    /* Note: ELCR is not reset */
> +    /* Note: ELCR and LTIM are not reset */
>   }
>   
>   static int pic_dispatch_pre_save(void *opaque)
> @@ -144,6 +144,24 @@ static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
>                      s->special_fully_nested_mode);
>   }
>   
> +static bool ltim_state_needed(void *opaque)
> +{
> +    PICCommonState *s = PIC_COMMON(opaque);
> +
> +    return !!s->ltim;
> +}
> +
> +static const VMStateDescription vmstate_pic_ltim = {
> +    .name = "i8259/ltim",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = ltim_state_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(ltim, PICCommonState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>   static const VMStateDescription vmstate_pic_common = {
>       .name = "i8259",
>       .version_id = 1,
> @@ -168,6 +186,10 @@ static const VMStateDescription vmstate_pic_common = {
>           VMSTATE_UINT8(single_mode, PICCommonState),
>           VMSTATE_UINT8(elcr, PICCommonState),
>           VMSTATE_END_OF_LIST()
> +    },
> +    .subsections = (const VMStateDescription*[]) {

Checkpatch will nag about it claiming that we need spaces between '*'. The maintainer
can fix it in-tree though.


Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>

> +        &vmstate_pic_ltim,
> +        NULL
>       }
>   };
>   
> diff --git a/include/hw/isa/i8259_internal.h b/include/hw/isa/i8259_internal.h
> index 155b098452..f9dcc4163e 100644
> --- a/include/hw/isa/i8259_internal.h
> +++ b/include/hw/isa/i8259_internal.h
> @@ -61,6 +61,7 @@ struct PICCommonState {
>       uint8_t single_mode; /* true if slave pic is not initialized */
>       uint8_t elcr; /* PIIX edge/trigger selection*/
>       uint8_t elcr_mask;
> +    uint8_t ltim; /* Edge/Level Bank Select (pre-PIIX, chip-wide) */
>       qemu_irq int_out[1];
>       uint32_t master; /* reflects /SP input pin */
>       uint32_t iobase;
Peter Maydell March 7, 2023, 1:38 p.m. UTC | #2
On Tue, 7 Mar 2023 at 13:36, Daniel Henrique Barboza
<danielhb413@gmail.com> wrote:
> On 3/7/23 08:42, BALATON Zoltan wrote:
> > @@ -168,6 +186,10 @@ static const VMStateDescription vmstate_pic_common = {
> >           VMSTATE_UINT8(single_mode, PICCommonState),
> >           VMSTATE_UINT8(elcr, PICCommonState),
> >           VMSTATE_END_OF_LIST()
> > +    },
> > +    .subsections = (const VMStateDescription*[]) {
>
> Checkpatch will nag about it claiming that we need spaces between '*'. The maintainer
> can fix it in-tree though.

checkpatch nags because it fails to correctly parse this piece
of C syntax and thinks the '*' is a multiplication operator;
we should just ignore it in this instance.

thanks
-- PMM
David Woodhouse March 7, 2023, 1:39 p.m. UTC | #3
On Tue, 2023-03-07 at 10:36 -0300, Daniel Henrique Barboza wrote:
> 
> Checkpatch will nag about it claiming that we need spaces between
> '*'. The maintainer can fix it in-tree though.

I saw that and explicitly didn't care. 3/5 of the existing examples
within the tree look like that one — which is how the docs tell us to
do it — so I figured checkpatch could just be sad.

> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>

Thanks.
BALATON Zoltan March 7, 2023, 2:18 p.m. UTC | #4
On Tue, 7 Mar 2023, Daniel Henrique Barboza wrote:
> On 3/7/23 08:42, BALATON Zoltan wrote:
>> From: David Woodhouse <dwmw2@infradead.org>
>> 
>> Back in the mists of time, before EISA came along and required per-pin
>> level control in the ELCR register, the i8259 had a single chip-wide
>> level-mode control in bit 3 of ICW1.
>> 
>> Even in the PIIX3 datasheet from 1996 this is documented as 'This bit is
>> disabled', but apparently MorphOS is using it in the version of the
>> i8259 which is in the Pegasos2 board as part of the VT8231 chipset.
>> 
>> It's easy enough to implement, and I think it's harmless enough to do so
>> unconditionally.
>> 
>> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
>> [balaton: updated commit message as asked by author]
>> Tested-by: BALATON Zoltan <balaton@eik.bme.hu>
>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>> ---
>>   hw/intc/i8259.c                 | 10 ++++------
>>   hw/intc/i8259_common.c          | 24 +++++++++++++++++++++++-
>>   include/hw/isa/i8259_internal.h |  1 +
>>   3 files changed, 28 insertions(+), 7 deletions(-)
>> 
>> diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
>> index 17910f3bcb..bbae2d87f4 100644
>> --- a/hw/intc/i8259.c
>> +++ b/hw/intc/i8259.c
>> @@ -133,7 +133,7 @@ static void pic_set_irq(void *opaque, int irq, int 
>> level)
>>       }
>>   #endif
>>   -    if (s->elcr & mask) {
>> +    if (s->ltim || (s->elcr & mask)) {
>>           /* level triggered */
>>           if (level) {
>>               s->irr |= mask;
>> @@ -167,7 +167,7 @@ static void pic_intack(PICCommonState *s, int irq)
>>           s->isr |= (1 << irq);
>>       }
>>       /* We don't clear a level sensitive interrupt here */
>> -    if (!(s->elcr & (1 << irq))) {
>> +    if (!s->ltim && !(s->elcr & (1 << irq))) {
>>           s->irr &= ~(1 << irq);
>>       }
>>       pic_update_irq(s);
>> @@ -224,6 +224,7 @@ static void pic_reset(DeviceState *dev)
>>       PICCommonState *s = PIC_COMMON(dev);
>>         s->elcr = 0;
>> +    s->ltim = 0;
>>       pic_init_reset(s);
>>   }
>>   @@ -243,10 +244,7 @@ static void pic_ioport_write(void *opaque, hwaddr 
>> addr64,
>>               s->init_state = 1;
>>               s->init4 = val & 1;
>>               s->single_mode = val & 2;
>> -            if (val & 0x08) {
>> -                qemu_log_mask(LOG_UNIMP,
>> -                              "i8259: level sensitive irq not 
>> supported\n");
>> -            }
>> +            s->ltim = val & 8;
>>           } else if (val & 0x08) {
>>               if (val & 0x04) {
>>                   s->poll = 1;
>> diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
>> index af2e4a2241..c931dc2d07 100644
>> --- a/hw/intc/i8259_common.c
>> +++ b/hw/intc/i8259_common.c
>> @@ -51,7 +51,7 @@ void pic_reset_common(PICCommonState *s)
>>       s->special_fully_nested_mode = 0;
>>       s->init4 = 0;
>>       s->single_mode = 0;
>> -    /* Note: ELCR is not reset */
>> +    /* Note: ELCR and LTIM are not reset */
>>   }
>>     static int pic_dispatch_pre_save(void *opaque)
>> @@ -144,6 +144,24 @@ static void pic_print_info(InterruptStatsProvider 
>> *obj, Monitor *mon)
>>                      s->special_fully_nested_mode);
>>   }
>>   +static bool ltim_state_needed(void *opaque)
>> +{
>> +    PICCommonState *s = PIC_COMMON(opaque);
>> +
>> +    return !!s->ltim;
>> +}
>> +
>> +static const VMStateDescription vmstate_pic_ltim = {
>> +    .name = "i8259/ltim",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .needed = ltim_state_needed,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT8(ltim, PICCommonState),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>>   static const VMStateDescription vmstate_pic_common = {
>>       .name = "i8259",
>>       .version_id = 1,
>> @@ -168,6 +186,10 @@ static const VMStateDescription vmstate_pic_common = {
>>           VMSTATE_UINT8(single_mode, PICCommonState),
>>           VMSTATE_UINT8(elcr, PICCommonState),
>>           VMSTATE_END_OF_LIST()
>> +    },
>> +    .subsections = (const VMStateDescription*[]) {
>
> Checkpatch will nag about it claiming that we need spaces between '*'. The 
> maintainer
> can fix it in-tree though.

I had that before in another patch but was told this is a checkpatch false 
positive I can disregard.

Regards,
BALATON Zoltan

>
> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>
>> +        &vmstate_pic_ltim,
>> +        NULL
>>       }
>>   };
>>   diff --git a/include/hw/isa/i8259_internal.h 
>> b/include/hw/isa/i8259_internal.h
>> index 155b098452..f9dcc4163e 100644
>> --- a/include/hw/isa/i8259_internal.h
>> +++ b/include/hw/isa/i8259_internal.h
>> @@ -61,6 +61,7 @@ struct PICCommonState {
>>       uint8_t single_mode; /* true if slave pic is not initialized */
>>       uint8_t elcr; /* PIIX edge/trigger selection*/
>>       uint8_t elcr_mask;
>> +    uint8_t ltim; /* Edge/Level Bank Select (pre-PIIX, chip-wide) */
>>       qemu_irq int_out[1];
>>       uint32_t master; /* reflects /SP input pin */
>>       uint32_t iobase;
>
>
Daniel Henrique Barboza March 7, 2023, 2:45 p.m. UTC | #5
On 3/7/23 10:39, David Woodhouse wrote:
> On Tue, 2023-03-07 at 10:36 -0300, Daniel Henrique Barboza wrote:
>>
>> Checkpatch will nag about it claiming that we need spaces between
>> '*'. The maintainer can fix it in-tree though.
> 
> I saw that and explicitly didn't care. 3/5 of the existing examples
> within the tree look like that one — which is how the docs tell us to
> do it — so I figured checkpatch could just be sad.

Regardless of how much we care about checkpatch happiness my r-b stands.

Peter said we can ignore it in this case, so yeah, checkpatch will probably
take a L.


Thanks,


Daniel

> 
>> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> 
> Thanks.
diff mbox series

Patch

diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index 17910f3bcb..bbae2d87f4 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -133,7 +133,7 @@  static void pic_set_irq(void *opaque, int irq, int level)
     }
 #endif
 
-    if (s->elcr & mask) {
+    if (s->ltim || (s->elcr & mask)) {
         /* level triggered */
         if (level) {
             s->irr |= mask;
@@ -167,7 +167,7 @@  static void pic_intack(PICCommonState *s, int irq)
         s->isr |= (1 << irq);
     }
     /* We don't clear a level sensitive interrupt here */
-    if (!(s->elcr & (1 << irq))) {
+    if (!s->ltim && !(s->elcr & (1 << irq))) {
         s->irr &= ~(1 << irq);
     }
     pic_update_irq(s);
@@ -224,6 +224,7 @@  static void pic_reset(DeviceState *dev)
     PICCommonState *s = PIC_COMMON(dev);
 
     s->elcr = 0;
+    s->ltim = 0;
     pic_init_reset(s);
 }
 
@@ -243,10 +244,7 @@  static void pic_ioport_write(void *opaque, hwaddr addr64,
             s->init_state = 1;
             s->init4 = val & 1;
             s->single_mode = val & 2;
-            if (val & 0x08) {
-                qemu_log_mask(LOG_UNIMP,
-                              "i8259: level sensitive irq not supported\n");
-            }
+            s->ltim = val & 8;
         } else if (val & 0x08) {
             if (val & 0x04) {
                 s->poll = 1;
diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
index af2e4a2241..c931dc2d07 100644
--- a/hw/intc/i8259_common.c
+++ b/hw/intc/i8259_common.c
@@ -51,7 +51,7 @@  void pic_reset_common(PICCommonState *s)
     s->special_fully_nested_mode = 0;
     s->init4 = 0;
     s->single_mode = 0;
-    /* Note: ELCR is not reset */
+    /* Note: ELCR and LTIM are not reset */
 }
 
 static int pic_dispatch_pre_save(void *opaque)
@@ -144,6 +144,24 @@  static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
                    s->special_fully_nested_mode);
 }
 
+static bool ltim_state_needed(void *opaque)
+{
+    PICCommonState *s = PIC_COMMON(opaque);
+
+    return !!s->ltim;
+}
+
+static const VMStateDescription vmstate_pic_ltim = {
+    .name = "i8259/ltim",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = ltim_state_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(ltim, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_pic_common = {
     .name = "i8259",
     .version_id = 1,
@@ -168,6 +186,10 @@  static const VMStateDescription vmstate_pic_common = {
         VMSTATE_UINT8(single_mode, PICCommonState),
         VMSTATE_UINT8(elcr, PICCommonState),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_pic_ltim,
+        NULL
     }
 };
 
diff --git a/include/hw/isa/i8259_internal.h b/include/hw/isa/i8259_internal.h
index 155b098452..f9dcc4163e 100644
--- a/include/hw/isa/i8259_internal.h
+++ b/include/hw/isa/i8259_internal.h
@@ -61,6 +61,7 @@  struct PICCommonState {
     uint8_t single_mode; /* true if slave pic is not initialized */
     uint8_t elcr; /* PIIX edge/trigger selection*/
     uint8_t elcr_mask;
+    uint8_t ltim; /* Edge/Level Bank Select (pre-PIIX, chip-wide) */
     qemu_irq int_out[1];
     uint32_t master; /* reflects /SP input pin */
     uint32_t iobase;