diff mbox

sparc escc IUS improvements (SunOS 4.1.4 fix)

Message ID 5e6dbb34b55746d1424618a2f9b881a9fc82f836.1281880453.git.atar4qemu@gmail.com
State New
Headers show

Commit Message

Artyom Tarasenko Aug. 15, 2010, 2:04 p.m. UTC
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(-)

Comments

Blue Swirl Aug. 16, 2010, 8:02 p.m. UTC | #1
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
>
>
diff mbox

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;