Patchwork sparc escc IUS improvements (SunOS 4.1.4 fix)

login
register
mail settings
Submitter Artyom Tarasenko
Date Aug. 15, 2010, 2:04 p.m.
Message ID <5e6dbb34b55746d1424618a2f9b881a9fc82f836.1281880453.git.atar4qemu@gmail.com>
Download mbox | patch
Permalink /patch/61746/
State New
Headers show

Comments

Artyom Tarasenko - Aug. 15, 2010, 2:04 p.m.
According to scc_escc_um.pdf:
 - Reset Highest IUS must update irq status to allow processing
   of the next priority interrupt.
 - rx interrupt has always higher priority than tx on same channel

The documentation only explicitly says that Reset Highest IUS
command (0x38) clears IUS bits, not that it clears the corresponding
interrupt too, so don't clear interrupts on this command.

The patch allows SunOS 4.1.4 to use the serial ports

Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
---
 hw/escc.c |   56 ++++++++++++++++++++++++++++++--------------------------
 1 files changed, 30 insertions(+), 26 deletions(-)
Blue Swirl - Aug. 16, 2010, 8:02 p.m.
Thanks, applied.

On Sun, Aug 15, 2010 at 2:04 PM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
> According to scc_escc_um.pdf:
>  - Reset Highest IUS must update irq status to allow processing
>   of the next priority interrupt.
>  - rx interrupt has always higher priority than tx on same channel
>
> The documentation only explicitly says that Reset Highest IUS
> command (0x38) clears IUS bits, not that it clears the corresponding
> interrupt too, so don't clear interrupts on this command.
>
> The patch allows SunOS 4.1.4 to use the serial ports
>
> Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
> ---
>  hw/escc.c |   56 ++++++++++++++++++++++++++++++--------------------------
>  1 files changed, 30 insertions(+), 26 deletions(-)
>
> diff --git a/hw/escc.c b/hw/escc.c
> index 6d2fd36..8714239 100644
> --- a/hw/escc.c
> +++ b/hw/escc.c
> @@ -65,6 +65,8 @@
>  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
>  *                                  serial mouse queue.
>  *                                  Implemented serial mouse protocol.
> + *
> + *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
>  */
>
>  #ifdef DEBUG_SERIAL
> @@ -279,7 +281,7 @@ static uint32_t get_queue(void *opaque)
>
>  static int escc_update_irq_chn(ChannelState *s)
>  {
> -    if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
> +    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
>          // tx ints enabled, pending
>          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
>            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
> @@ -342,24 +344,22 @@ static void escc_reset(DeviceState *d)
>  static inline void set_rxint(ChannelState *s)
>  {
>     s->rxint = 1;
> -    if (!s->txint_under_svc) {
> -        s->rxint_under_svc = 1;
> -        if (s->chn == chn_a) {
> -            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
> -                s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
> -            else
> -                s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
> -        } else {
> -            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
> -                s->rregs[R_IVEC] = IVEC_HIRXINTB;
> -            else
> -                s->rregs[R_IVEC] = IVEC_LORXINTB;
> -        }
> -    }
> -    if (s->chn == chn_a)
> +    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
> +       than chn_a rx/tx/special_condition service*/
> +    s->rxint_under_svc = 1;
> +    if (s->chn == chn_a) {
>         s->rregs[R_INTR] |= INTR_RXINTA;
> -    else
> +        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
> +            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
> +        else
> +            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
> +    } else {
>         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
> +        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
> +            s->rregs[R_IVEC] = IVEC_HIRXINTB;
> +        else
> +            s->rregs[R_IVEC] = IVEC_LORXINTB;
> +    }
>     escc_update_irq(s);
>  }
>
> @@ -369,19 +369,17 @@ static inline void set_txint(ChannelState *s)
>     if (!s->rxint_under_svc) {
>         s->txint_under_svc = 1;
>         if (s->chn == chn_a) {
> +            s->rregs[R_INTR] |= INTR_TXINTA;
>             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
>                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
>             else
>                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
>         } else {
>             s->rregs[R_IVEC] = IVEC_TXINTB;
> +            s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
>         }
> -    }
> -    if (s->chn == chn_a)
> -        s->rregs[R_INTR] |= INTR_TXINTA;
> -    else
> -        s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
>     escc_update_irq(s);
> +    }
>  }
>
>  static inline void clr_rxint(ChannelState *s)
> @@ -417,6 +415,7 @@ static inline void clr_txint(ChannelState *s)
>             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
>         s->rregs[R_INTR] &= ~INTR_TXINTA;
>     } else {
> +        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
>         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
>             s->rregs[R_IVEC] = IVEC_HINOINT;
>         else
> @@ -515,10 +514,15 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
>                 clr_txint(s);
>                 break;
>             case CMD_CLR_IUS:
> -                if (s->rxint_under_svc)
> -                    clr_rxint(s);
> -                else if (s->txint_under_svc)
> -                    clr_txint(s);
> +                if (s->rxint_under_svc) {
> +                    s->rxint_under_svc = 0;
> +                    if (s->txint) {
> +                        set_txint(s);
> +                    }
> +                } else if (s->txint_under_svc) {
> +                    s->txint_under_svc = 0;
> +                }
> +                escc_update_irq(s);
>                 break;
>             default:
>                 break;
> --
> 1.7.2.1
>
>

Patch

diff --git a/hw/escc.c b/hw/escc.c
index 6d2fd36..8714239 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -65,6 +65,8 @@ 
  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
  *                                  serial mouse queue.
  *                                  Implemented serial mouse protocol.
+ *
+ *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
  */
 
 #ifdef DEBUG_SERIAL
@@ -279,7 +281,7 @@  static uint32_t get_queue(void *opaque)
 
 static int escc_update_irq_chn(ChannelState *s)
 {
-    if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
          // tx ints enabled, pending
          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
@@ -342,24 +344,22 @@  static void escc_reset(DeviceState *d)
 static inline void set_rxint(ChannelState *s)
 {
     s->rxint = 1;
-    if (!s->txint_under_svc) {
-        s->rxint_under_svc = 1;
-        if (s->chn == chn_a) {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
-            else
-                s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
-        } else {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->rregs[R_IVEC] = IVEC_HIRXINTB;
-            else
-                s->rregs[R_IVEC] = IVEC_LORXINTB;
-        }
-    }
-    if (s->chn == chn_a)
+    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+       than chn_a rx/tx/special_condition service*/
+    s->rxint_under_svc = 1;
+    if (s->chn == chn_a) {
         s->rregs[R_INTR] |= INTR_RXINTA;
-    else
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+    } else {
         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HIRXINTB;
+        else
+            s->rregs[R_IVEC] = IVEC_LORXINTB;
+    }
     escc_update_irq(s);
 }
 
@@ -369,19 +369,17 @@  static inline void set_txint(ChannelState *s)
     if (!s->rxint_under_svc) {
         s->txint_under_svc = 1;
         if (s->chn == chn_a) {
+            s->rregs[R_INTR] |= INTR_TXINTA;
             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
             else
                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
         } else {
             s->rregs[R_IVEC] = IVEC_TXINTB;
+            s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
         }
-    }
-    if (s->chn == chn_a)
-        s->rregs[R_INTR] |= INTR_TXINTA;
-    else
-        s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
     escc_update_irq(s);
+    }
 }
 
 static inline void clr_rxint(ChannelState *s)
@@ -417,6 +415,7 @@  static inline void clr_txint(ChannelState *s)
             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
         s->rregs[R_INTR] &= ~INTR_TXINTA;
     } else {
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
             s->rregs[R_IVEC] = IVEC_HINOINT;
         else
@@ -515,10 +514,15 @@  static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                 clr_txint(s);
                 break;
             case CMD_CLR_IUS:
-                if (s->rxint_under_svc)
-                    clr_rxint(s);
-                else if (s->txint_under_svc)
-                    clr_txint(s);
+                if (s->rxint_under_svc) {
+                    s->rxint_under_svc = 0;
+                    if (s->txint) {
+                        set_txint(s);
+                    }
+                } else if (s->txint_under_svc) {
+                    s->txint_under_svc = 0;
+                }
+                escc_update_irq(s);
                 break;
             default:
                 break;