[PATCH v6 08/15] emul/ns16x50: implement MCR/MSR registers

dmukhin@xen.org posted 15 patches 5 months, 1 week ago
There is a newer version of this series
[PATCH v6 08/15] emul/ns16x50: implement MCR/MSR registers
Posted by dmukhin@xen.org 5 months, 1 week ago
From: Denis Mukhin <dmukhin@ford.com> 

Add MCR/MSR registers emulation to the I/O port handler.

Add implementation of ns16x50_iir_check_msi().

Signed-off-by: Denis Mukhin <dmukhin@ford.com>
---
Changes in v5:
- Moved earlier in the series
- Link to v5: https://lore.kernel.org/xen-devel/20250828235409.2835815-10-dmukhin@ford.com/
---
 xen/common/emul/vuart/ns16x50.c | 62 ++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index 9d1fe0284362..a8ec9f6c3a04 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -108,7 +108,7 @@ static bool cf_check ns16x50_iir_check_thr(const struct vuart_ns16x50 *vdev)
 
 static bool cf_check ns16x50_iir_check_msi(const struct vuart_ns16x50 *vdev)
 {
-    return false;
+    return vdev->regs[UART_MSR] & UART_MSR_CHANGE;
 }
 
 /*
@@ -230,12 +230,63 @@ static int ns16x50_io_write8(
             regs[UART_LCR] = val;
             break;
 
+        case UART_MCR: {
+            uint8_t msr_curr, msr_next, msr_delta;
+
+            msr_curr = regs[UART_MSR];
+            msr_next = 0;
+            msr_delta = 0;
+
+            if ( val & UART_MCR_RESERVED0 )
+                ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %x\n",
+                             UART_MCR_RESERVED0);
+
+            if ( val & UART_MCR_TCRTLR )
+                ns16x50_warn(vdev, "MCR: not supported: %x\n",
+                             UART_MCR_TCRTLR);
+
+            if ( val & UART_MCR_RESERVED1 )
+                ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %x\n",
+                             UART_MCR_RESERVED1);
+
+            /* Set modem status */
+            if ( val & UART_MCR_LOOP )
+            {
+                if ( val & UART_MCR_DTR )
+                    msr_next |= UART_MSR_DSR;
+                if ( val & UART_MCR_RTS )
+                    msr_next |= UART_MSR_CTS;
+                if ( val & UART_MCR_OUT1 )
+                    msr_next |= UART_MSR_RI;
+                if ( val & UART_MCR_OUT2 )
+                    msr_next |= UART_MSR_DCD;
+            }
+            else
+                msr_next |= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+
+            /* Calculate changes in modem status */
+            if ( (msr_curr & UART_MSR_CTS) ^ (msr_next & UART_MSR_CTS) )
+                msr_delta |= UART_MSR_DCTS;
+            if ( (msr_curr & UART_MSR_DSR) ^ (msr_next & UART_MSR_DSR) )
+                msr_delta |= UART_MSR_DDSR;
+            if ( (msr_curr & UART_MSR_RI)  & (msr_next & UART_MSR_RI) )
+                msr_delta |= UART_MSR_TERI;
+            if ( (msr_curr & UART_MSR_DCD) ^ (msr_next & UART_MSR_DCD) )
+                msr_delta |= UART_MSR_DDCD;
+
+            regs[UART_MCR] = val & UART_MCR_MASK;
+            regs[UART_MSR] = msr_next | msr_delta;
+
+            break;
+        }
+
         /* NB: Firmware (e.g. OVMF) may rely on SCR presence. */
         case UART_SCR:
             regs[UART_SCR] = val;
             break;
 
         case UART_LSR: /* RO */
+        case UART_MSR: /* RO */
         default:
             rc = -EINVAL;
             break;
@@ -321,11 +372,20 @@ static int ns16x50_io_read8(
             val = regs[UART_LCR];
             break;
 
+        case UART_MCR:
+            val = regs[UART_MCR];
+            break;
+
         case UART_LSR:
             val = regs[UART_LSR] | UART_LSR_THRE | UART_LSR_TEMT;
             regs[UART_LSR] = val & ~UART_LSR_MASK;
             break;
 
+        case UART_MSR:
+            val = regs[UART_MSR];
+            regs[UART_MSR] &= ~UART_MSR_CHANGE;
+            break;
+
         case UART_SCR:
             val = regs[UART_SCR];
             break;
-- 
2.51.0
Re: [PATCH v6 08/15] emul/ns16x50: implement MCR/MSR registers
Posted by Stefano Stabellini 5 months, 1 week ago
On Fri, 5 Sep 2025, dmukhin@xen.org wrote:
> From: Denis Mukhin <dmukhin@ford.com> 
> 
> Add MCR/MSR registers emulation to the I/O port handler.
> 
> Add implementation of ns16x50_iir_check_msi().
> 
> Signed-off-by: Denis Mukhin <dmukhin@ford.com>
> ---
> Changes in v5:
> - Moved earlier in the series
> - Link to v5: https://lore.kernel.org/xen-devel/20250828235409.2835815-10-dmukhin@ford.com/
> ---
>  xen/common/emul/vuart/ns16x50.c | 62 ++++++++++++++++++++++++++++++++-
>  1 file changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
> index 9d1fe0284362..a8ec9f6c3a04 100644
> --- a/xen/common/emul/vuart/ns16x50.c
> +++ b/xen/common/emul/vuart/ns16x50.c
> @@ -108,7 +108,7 @@ static bool cf_check ns16x50_iir_check_thr(const struct vuart_ns16x50 *vdev)
>  
>  static bool cf_check ns16x50_iir_check_msi(const struct vuart_ns16x50 *vdev)
>  {
> -    return false;
> +    return vdev->regs[UART_MSR] & UART_MSR_CHANGE;
>  }
>  
>  /*
> @@ -230,12 +230,63 @@ static int ns16x50_io_write8(
>              regs[UART_LCR] = val;
>              break;
>  
> +        case UART_MCR: {
> +            uint8_t msr_curr, msr_next, msr_delta;
> +
> +            msr_curr = regs[UART_MSR];
> +            msr_next = 0;
> +            msr_delta = 0;
> +
> +            if ( val & UART_MCR_RESERVED0 )
> +                ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %x\n",
> +                             UART_MCR_RESERVED0);
> +
> +            if ( val & UART_MCR_TCRTLR )
> +                ns16x50_warn(vdev, "MCR: not supported: %x\n",
> +                             UART_MCR_TCRTLR);
> +
> +            if ( val & UART_MCR_RESERVED1 )
> +                ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %x\n",
> +                             UART_MCR_RESERVED1);
> +
> +            /* Set modem status */
> +            if ( val & UART_MCR_LOOP )
> +            {
> +                if ( val & UART_MCR_DTR )
> +                    msr_next |= UART_MSR_DSR;
> +                if ( val & UART_MCR_RTS )
> +                    msr_next |= UART_MSR_CTS;
> +                if ( val & UART_MCR_OUT1 )
> +                    msr_next |= UART_MSR_RI;
> +                if ( val & UART_MCR_OUT2 )
> +                    msr_next |= UART_MSR_DCD;
> +            }
> +            else
> +                msr_next |= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
> +
> +            /* Calculate changes in modem status */
> +            if ( (msr_curr & UART_MSR_CTS) ^ (msr_next & UART_MSR_CTS) )
> +                msr_delta |= UART_MSR_DCTS;
> +            if ( (msr_curr & UART_MSR_DSR) ^ (msr_next & UART_MSR_DSR) )
> +                msr_delta |= UART_MSR_DDSR;
> +            if ( (msr_curr & UART_MSR_RI)  & (msr_next & UART_MSR_RI) )
> +                msr_delta |= UART_MSR_TERI;

Should this be:

if ( (msr_curr & UART_MSR_RI) && !(msr_next & UART_MSR_RI) )
    msr_delta |= UART_MSR_TERI;

?


> +            if ( (msr_curr & UART_MSR_DCD) ^ (msr_next & UART_MSR_DCD) )
> +                msr_delta |= UART_MSR_DDCD;
> +
> +            regs[UART_MCR] = val & UART_MCR_MASK;
> +            regs[UART_MSR] = msr_next | msr_delta;
> +
> +            break;
> +        }
Re: [PATCH v6 08/15] emul/ns16x50: implement MCR/MSR registers
Posted by dmukhin@xen.org 5 months ago
On Fri, Sep 05, 2025 at 06:42:23PM -0700, Stefano Stabellini wrote:
> On Fri, 5 Sep 2025, dmukhin@xen.org wrote:
> > From: Denis Mukhin <dmukhin@ford.com> 
[..]
> > +            /* Calculate changes in modem status */
> > +            if ( (msr_curr & UART_MSR_CTS) ^ (msr_next & UART_MSR_CTS) )
> > +                msr_delta |= UART_MSR_DCTS;
> > +            if ( (msr_curr & UART_MSR_DSR) ^ (msr_next & UART_MSR_DSR) )
> > +                msr_delta |= UART_MSR_DDSR;
> > +            if ( (msr_curr & UART_MSR_RI)  & (msr_next & UART_MSR_RI) )
> > +                msr_delta |= UART_MSR_TERI;
> 
> Should this be:
> 
> if ( (msr_curr & UART_MSR_RI) && !(msr_next & UART_MSR_RI) )
>     msr_delta |= UART_MSR_TERI;
> 
> ?

Thanks for the catch!

TL16C550C spec (7.7.10 Modem Status Register (MSR)) says TERI is set on
RI's 0->1 transition:

   if ( !(msr_curr & UART_MSR_RI) && (msr_next & UART_MSR_RI) )