qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] ESCC2
@ 2020-06-17  8:23 Jasper Lowell
  2020-06-17  8:23 ` [PATCH 1/8] hw/char/escc2: Add device Jasper Lowell
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

I've been working on improving Solaris 10 emulation for the SPARC64
Sun4u architecture with the goal of a working shell. Currently, Solaris
10 boots with a number of errors before displaying the prompt of an
otherwise unresponsive installer shell. It's been mentioned that this
problem may not be isolated to Solaris 10 but may affect derivatives of
OpenSolaris including illumos.

From what I can tell, Solaris 10 never attempts to use the 16550A UART
for the serial console. The kernel will probe registers to identify the
device but will not use it for receiving or transmitting. The kernel
only prints to the console using the prom interface that OpenBIOS
provides. It's difficult to ascertain what the problem is because there
is no visibility into the kernel. The 16550A UART on the Ultra 5
(Darwin), the machine that QEMU Sun4u is modelled against, is used for
the keyboard/mouse (SuperIO) and is not traditionally used for the
serial tty. Instead, the SAB 82532 ESCC2 is used to provide ttya and
ttyb on this system. This patch exists to increment QEMU Sun4u towards
being hardware faithful.

The SAB 82532 ESCC2 is complex because of the jungle of features that it
provides. Linux and OpenBSD only use a small subset of features
restricted to the ASYNC serial mode. The ASYNC serial mode is
relatively simple to implement in isolation. I have made progress on a
patch series that supports all serial modes, along with transitioning
between them, but I have decided against submitting it. The serial
controller appears to multiplex bit positions in registers across serial
modes while preserving the bits themselves. This means that some 8-bit
registers need to keep track of more than 8-bits of data and that the
interpretation of the value the register holds depends on the selected
serial mode. It's not ideal having a copy of each register for each
serial mode because some bits are shared across some of the register
modes. An added difficulty is that the manual doesn't document this
behaviour well and its unclear what exactly happens when there is a
transition in the selected serial mode. I've avoided depending on
registers being uint8_t and have made use of macros so that the backend
implementation of each register can be changed at a later date when
supporting other serial modes. If I have the opportunity to test real
hardware, or it becomes clear that HDLC/SDLC/BISYNC support is needed,
I'll look at upstreaming the other changes that I have.

I have written a bare-bones patch for OpenBIOS that adds this device to
the device tree. With that applied, Solaris identifies and attaches the
device successfully but does not interact with it further - similar to
the 16550A UART. I did notice, however, that Solaris 10 entered an
interrupt routine for this device when the network card was being
configured. I couldn't manage to provoke this behaviour for the 16550A
so this might be some small success. I strongly suspect that the
interrupt is a spurious interrupt caused by misconfiguration of the
devices in the firmware but I have not investigated this further.

Solaris 10, judging from the OpenSolaris source code, determines
stdin/stdout for the console by examining the stdin/stdout properties
under /chosen in the device tree. Naturally, this is done with the prom
interface. From what I can tell, to set these properties to the ESCC2
node it's necessary to change stdin/stdout for OpenBIOS completely. This
requires a device driver. I have made some progress on an OpenBIOS
device driver for the ESCC2 but it's taking longer than expected to
completely replace the 16550A and it's unlikely that I will have this
finished soon. It's possible that Solaris 10 emulation for this platform
will improve once that work is finished but it's unclear.

This is my first patch series for QEMU so it's possible that I've made
mistakes in the contribution process - sorry in advance.

Jasper Lowell (8):
  hw/char/escc2: Add device
  hw/char/escc2: Handle interrupt generation
  hw/char/escc2: Add character device backend
  hw/char/escc2: Add clock generation
  hw/char/escc2: Add Receiver Reset (RRES) command
  hw/char/escc2: Add RFRD command
  hw/char/escc2: Add Transmit Frame (XF) command
  hw/char/escc2: Add XRES command

 hw/char/Kconfig         |    8 +
 hw/char/Makefile.objs   |    1 +
 hw/char/escc2.c         | 1135 +++++++++++++++++++++++++++++++++++++++
 hw/char/trace-events    |    6 +
 include/hw/char/escc2.h |   17 +
 5 files changed, 1167 insertions(+)
 create mode 100644 hw/char/escc2.c
 create mode 100644 include/hw/char/escc2.h

-- 
2.26.2



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/8] hw/char/escc2: Add device
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
@ 2020-06-17  8:23 ` Jasper Lowell
  2020-06-17  8:23 ` [PATCH 2/8] hw/char/escc2: Handle interrupt generation Jasper Lowell
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

The Ultra 5 (Darwin) machine that is emulated for the Sun4u architecture
ships with a SAB 82532 ESCC2 device that is used for providing the
default ttya/ttyb serial consoles. This device is introduced to
increment Sun4u emulation towards being hardware faithful. ISA support
is included so that the device can be attached to the Sun ebus.

Due to the complexity of the chip, the SAB 82532 ESCC2 is assumed to be
configured and used in the ASYNC serial mode. This is the case for
typical operating system drivers like those in Linux and OpenBSD.

While ASYNC serial mode is assumed, the implementation is designed with
the assumption that the full set of serial modes may be added at a later
date. Registers can not be represented as uint8_t when more than a
single serial mode is correctly implemented and so, the design avoids
assuming the data structure used for registers. Avoiding this assumption
leads to loops, rather than memset, along with a verbose switch case.
The verbose switch case also has the benefit of preemptively detangling
the jungle of features that the device supports.

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/Kconfig         |   8 +
 hw/char/Makefile.objs   |   1 +
 hw/char/escc2.c         | 581 ++++++++++++++++++++++++++++++++++++++++
 hw/char/trace-events    |   4 +
 include/hw/char/escc2.h |  17 ++
 5 files changed, 611 insertions(+)
 create mode 100644 hw/char/escc2.c
 create mode 100644 include/hw/char/escc2.h

diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 40e7a8b8bb..87352a75d8 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -1,6 +1,14 @@
 config ESCC
     bool
 
+config ESCC2
+    bool
+
+config ESCC2_ISA
+    bool
+    depends on ISA_BUS
+    select ESCC2
+
 config PARALLEL
     bool
     default y
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 9e9a6c1aff..fd4766fd36 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -1,5 +1,6 @@
 common-obj-$(CONFIG_IPACK) += ipoctal232.o
 common-obj-$(CONFIG_ESCC) += escc.o
+common-obj-$(CONFIG_ESCC2) += escc2.o
 common-obj-$(CONFIG_NRF51_SOC) += nrf51_uart.o
 common-obj-$(CONFIG_PARALLEL) += parallel.o
 common-obj-$(CONFIG_ISA_BUS) += parallel-isa.o
diff --git a/hw/char/escc2.c b/hw/char/escc2.c
new file mode 100644
index 0000000000..94528b8a4c
--- /dev/null
+++ b/hw/char/escc2.c
@@ -0,0 +1,581 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Enhanced Serial Communication Controller (ESCC2 v3.2).
+ * Modelled according to the user manual (version 07.96).
+ *
+ * Copyright (C) 2020 Jasper Lowell
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/escc2.h"
+#include "hw/isa/isa.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "sysemu/reset.h"
+#include "trace.h"
+
+/* STAR. */
+#define REGISTER_STAR_OFFSET                    0x20
+
+/* CMDR. */
+#define REGISTER_CMDR_OFFSET                    0x20
+
+/* MODE. */
+#define REGISTER_MODE_OFFSET                    0x22
+
+/* TIMR. */
+#define REGISTER_TIMR_OFFSET                    0x23
+
+/* XON. */
+#define REGISTER_XON_OFFSET                     0x24
+
+/* XOFF. */
+#define REGISTER_XOFF_OFFSET                    0x25
+
+/* TCR. */
+#define REGISTER_TCR_OFFSET                     0x26
+
+/* DAFO. */
+#define REGISTER_DAFO_OFFSET                    0x27
+
+/* RFC. */
+#define REGISTER_RFC_OFFSET                     0x28
+
+/* RBCL. */
+#define REGISTER_RBCL_OFFSET                    0x2a
+
+/* XBCL. */
+#define REGISTER_XBCL_OFFSET                    0x2a
+
+/* RBCH. */
+#define REGISTER_RBCH_OFFSET                    0x2b
+
+/* XBCH. */
+#define REGISTER_XBCH_OFFSET                    0x2b
+
+/* CCR0. */
+#define REGISTER_CCR0_OFFSET                    0x2c
+
+/* CCR1. */
+#define REGISTER_CCR1_OFFSET                    0x2d
+
+/* CCR2. */
+#define REGISTER_CCR2_OFFSET                    0x2e
+
+/* CCR3. */
+#define REGISTER_CCR3_OFFSET                    0x2f
+
+/* TSAX. */
+#define REGISTER_TSAX_OFFSET                    0x30
+
+/* TSAR. */
+#define REGISTER_TSAR_OFFSET                    0x31
+
+/* XCCR. */
+#define REGISTER_XCCR_OFFSET                    0x32
+
+/* RCCR. */
+#define REGISTER_RCCR_OFFSET                    0x33
+
+/* VSTR. */
+#define REGISTER_VSTR_OFFSET                    0x34
+
+/* BGR. */
+#define REGISTER_BGR_OFFSET                     0x34
+
+/* TIC. */
+#define REGISTER_TIC_OFFSET                     0x35
+
+/* MXN. */
+#define REGISTER_MXN_OFFSET                     0x36
+
+/* MXF. */
+#define REGISTER_MXF_OFFSET                     0x37
+
+/* GIS. */
+#define REGISTER_GIS_OFFSET                     0x38
+
+/* IVA. */
+#define REGISTER_IVA_OFFSET                     0x38
+
+/* IPC. */
+#define REGISTER_IPC_OFFSET                     0x39
+
+/* ISR0. */
+#define REGISTER_ISR0_OFFSET                    0x3a
+
+/* IMR0. */
+#define REGISTER_IMR0_OFFSET                    0x3a
+
+/* ISR1. */
+#define REGISTER_ISR1_OFFSET                    0x3b
+
+/* IMR1. */
+#define REGISTER_IMR1_OFFSET                    0x3b
+
+/* PVR. */
+#define REGISTER_PVR_OFFSET                     0x3c
+
+/* PIS. */
+#define REGISTER_PIS_OFFSET                     0x3d
+
+/* PIM. */
+#define REGISTER_PIM_OFFSET                     0x3d
+
+/* PCR. */
+#define REGISTER_PCR_OFFSET                     0x3e
+
+/* CCR4. */
+#define REGISTER_CCR4_OFFSET                    0x3f
+
+enum {
+    REGISTER_STAR = 0,
+    REGISTER_CMDR,
+    REGISTER_MODE,
+    REGISTER_TIMR,
+    REGISTER_XON,
+    REGISTER_XOFF,
+    REGISTER_TCR,
+    REGISTER_DAFO,
+    REGISTER_RFC,
+    REGISTER_RBCL,
+    REGISTER_XBCL,
+    REGISTER_RBCH,
+    REGISTER_XBCH,
+    REGISTER_CCR0,
+    REGISTER_CCR1,
+    REGISTER_CCR2,
+    REGISTER_CCR3,
+    REGISTER_TSAX,
+    REGISTER_TSAR,
+    REGISTER_XCCR,
+    REGISTER_RCCR,
+    REGISTER_VSTR,
+    REGISTER_BGR,
+    REGISTER_TIC,
+    REGISTER_MXN,
+    REGISTER_MXF,
+    REGISTER_GIS,
+    REGISTER_IVA,
+    REGISTER_IPC,
+    REGISTER_ISR0,
+    REGISTER_IMR0,
+    REGISTER_ISR1,
+    REGISTER_IMR1,
+    REGISTER_PVR,
+    REGISTER_PIS,
+    REGISTER_PIM,
+    REGISTER_PCR,
+    REGISTER_CCR4,
+    /* End. */
+    REGISTER_COUNT
+};
+
+typedef struct ESCC2State ESCC2State;
+
+#define CHANNEL_FIFO_LENGTH                     0x20
+typedef struct ESCC2ChannelState {
+    ESCC2State *controller;
+
+    /*
+     * The SAB 82532 ships with 64 byte FIFO queues for transmitting and
+     * receiving but only 32 bytes are addressable.
+     */
+    uint8_t fifo_receive[CHANNEL_FIFO_LENGTH];
+    uint8_t fifo_transmit[CHANNEL_FIFO_LENGTH];
+
+    uint8_t register_set[REGISTER_COUNT];
+} ESCC2ChannelState;
+
+#define CHANNEL_A_OFFSET                        0x0
+#define CHANNEL_B_OFFSET                        0x40
+#define CHANNEL_LENGTH                          0x40
+
+#define REGISTER_READ(channel, idx) \
+    ((channel)->register_set[(idx)])
+#define REGISTER_WRITE(channel, idx, value) \
+    ((channel)->register_set[(idx)] = (value))
+
+enum {
+    CHANNEL_A = 0,
+    CHANNEL_B,
+    /* End. */
+    CHANNEL_COUNT
+};
+
+struct ESCC2State {
+    DeviceState parent;
+
+    MemoryRegion io;
+    ESCC2ChannelState channel[CHANNEL_COUNT];
+};
+
+#define CONTROLLER_CHANNEL_A(controller) (&(controller)->channel[CHANNEL_A])
+#define CONTROLLER_CHANNEL_B(controller) (&(controller)->channel[CHANNEL_B])
+#define CHANNEL_CHAR(channel) \
+    ((channel) == CONTROLLER_CHANNEL_A((channel)->controller) ? 'A' : 'B')
+
+typedef struct ESCC2ISAState {
+    ISADevice parent;
+    uint32_t iobase;
+    struct ESCC2State controller;
+} ESCC2ISAState;
+
+static void escc2_channel_reset(ESCC2ChannelState *channel)
+{
+    unsigned int i;
+
+    memset(channel->fifo_receive, 0, sizeof(channel->fifo_receive));
+    memset(channel->fifo_transmit, 0, sizeof(channel->fifo_transmit));
+    for (i = 0; i < REGISTER_COUNT; i++) {
+        channel->register_set[i] = 0;
+    }
+
+    channel->register_set[REGISTER_STAR] = 0x40;
+    channel->register_set[REGISTER_VSTR] = 0x2;
+}
+
+static void escc2_reset(void *opaque)
+{
+    unsigned int i;
+    ESCC2State *controller = opaque;
+
+    for (i = 0; i < CHANNEL_COUNT; i++) {
+        escc2_channel_reset(&controller->channel[i]);
+    }
+}
+
+static uint64_t escc2_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint8_t value, offset;
+    ESCC2State *controller;
+    ESCC2ChannelState *channel;
+
+    assert(addr < (CHANNEL_COUNT * CHANNEL_LENGTH));
+    assert(size == sizeof(uint8_t));
+
+    controller = opaque;
+    if (addr < CHANNEL_LENGTH) {
+        channel = CONTROLLER_CHANNEL_A(controller);
+        offset = addr;
+    } else {
+        channel = CONTROLLER_CHANNEL_B(controller);
+        offset = addr - CHANNEL_LENGTH;
+    }
+
+    switch (offset) {
+    case 0 ... (CHANNEL_FIFO_LENGTH - 1):
+        value = channel->fifo_receive[offset];
+        break;
+    case REGISTER_STAR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_STAR);
+        break;
+    case REGISTER_MODE_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_MODE);
+        break;
+    case REGISTER_TIMR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_TIMR);
+        break;
+    case REGISTER_XON_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_XON);
+        break;
+    case REGISTER_XOFF_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_XOFF);
+        break;
+    case REGISTER_TCR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_TCR);
+        break;
+    case REGISTER_DAFO_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_DAFO);
+        break;
+    case REGISTER_RFC_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_RFC);
+        break;
+    case REGISTER_RBCL_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_RBCL);
+        break;
+    case REGISTER_RBCH_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_RBCH);
+        break;
+    case REGISTER_CCR0_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_CCR0);
+        break;
+    case REGISTER_CCR1_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_CCR1);
+        break;
+    case REGISTER_CCR2_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_CCR2);
+        break;
+    case REGISTER_CCR3_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_CCR3);
+        break;
+    case REGISTER_VSTR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_VSTR);
+        break;
+    case REGISTER_GIS_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_GIS);
+        break;
+    case REGISTER_IPC_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_IPC);
+        break;
+    case REGISTER_ISR0_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_ISR0);
+        break;
+    case REGISTER_ISR1_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_ISR1);
+        break;
+    case REGISTER_PVR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_PVR);
+        break;
+    case REGISTER_PIS_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_PIS);
+        break;
+    case REGISTER_PCR_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_PCR);
+        break;
+    case REGISTER_CCR4_OFFSET:
+        value = REGISTER_READ(channel, REGISTER_CCR4);
+        break;
+    default:
+        value = 0;
+        break;
+    }
+
+    trace_escc2_mem_read(CHANNEL_CHAR(channel), offset, value);
+    return value;
+}
+
+static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
+        unsigned size)
+{
+    uint8_t offset;
+    ESCC2State *controller;
+    ESCC2ChannelState *channel;
+
+    assert(addr < (CHANNEL_COUNT * CHANNEL_LENGTH));
+    assert(size == sizeof(uint8_t));
+    assert(value <= 0xff);
+
+    controller = opaque;
+    if (addr < CHANNEL_LENGTH) {
+        channel = CONTROLLER_CHANNEL_A(controller);
+        offset = addr;
+    } else {
+        channel = CONTROLLER_CHANNEL_B(controller);
+        offset = addr - CHANNEL_LENGTH;
+    }
+
+    switch (offset) {
+    case 0 ... (CHANNEL_FIFO_LENGTH - 1):
+        channel->fifo_transmit[offset] = value;
+        break;
+    case REGISTER_CMDR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CMDR, value);
+        break;
+    case REGISTER_MODE_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_MODE, value);
+        break;
+    case REGISTER_TIMR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_TIMR, value);
+        break;
+    case REGISTER_XON_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_XON, value);
+        break;
+    case REGISTER_XOFF_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_XOFF, value);
+        break;
+    case REGISTER_TCR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_TCR, value);
+        break;
+    case REGISTER_DAFO_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_DAFO, value);
+        break;
+    case REGISTER_RFC_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_RFC, value);
+        break;
+    case REGISTER_XBCL_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_XBCL, value);
+        break;
+    case REGISTER_XBCH_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_XBCH, value);
+        break;
+    case REGISTER_CCR0_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CCR0, value);
+        break;
+    case REGISTER_CCR1_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CCR1, value);
+        break;
+    case REGISTER_CCR2_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CCR2, value);
+        break;
+    case REGISTER_CCR3_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CCR3, value);
+        break;
+    case REGISTER_TSAX_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_TSAX, value);
+        break;
+    case REGISTER_TSAR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_TSAR, value);
+        break;
+    case REGISTER_XCCR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_XCCR, value);
+        break;
+    case REGISTER_RCCR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_RCCR, value);
+        break;
+    case REGISTER_BGR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_BGR, value);
+        break;
+    case REGISTER_TIC_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_TIC, value);
+        break;
+    case REGISTER_MXN_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_MXN, value);
+        break;
+    case REGISTER_MXF_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_MXF, value);
+        break;
+    case REGISTER_IVA_OFFSET:
+        REGISTER_WRITE(CONTROLLER_CHANNEL_A(controller), REGISTER_IVA, value);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_B(controller), REGISTER_IVA, value);
+        break;
+    case REGISTER_IPC_OFFSET:
+        REGISTER_WRITE(CONTROLLER_CHANNEL_A(controller), REGISTER_IPC, value);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_B(controller), REGISTER_IPC, value);
+        break;
+    case REGISTER_IMR0_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_IMR0, value);
+        break;
+    case REGISTER_IMR1_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_IMR1, value);
+        break;
+    case REGISTER_PVR_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_PVR, value);
+        break;
+    case REGISTER_PIM_OFFSET:
+        REGISTER_WRITE(CONTROLLER_CHANNEL_A(controller), REGISTER_PIM, value);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_B(controller), REGISTER_PIM, value);
+        break;
+    case REGISTER_PCR_OFFSET:
+        REGISTER_WRITE(CONTROLLER_CHANNEL_A(controller), REGISTER_PCR, value);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_B(controller), REGISTER_PCR, value);
+        break;
+    case REGISTER_CCR4_OFFSET:
+        REGISTER_WRITE(channel, REGISTER_CCR4, value);
+        break;
+    default:
+        /* Registers do not exhaustively cover the addressable region. */
+        break;
+    }
+
+    trace_escc2_mem_write(CHANNEL_CHAR(channel), offset, value);
+}
+
+static void escc2_realize(DeviceState *dev, Error **errp)
+{
+    unsigned int i;
+    ESCC2ChannelState *channel;
+    ESCC2State *controller = ESCC2(dev);
+
+    for (i = 0; i < CHANNEL_COUNT; i++) {
+        channel = &controller->channel[i];
+        channel->controller = controller;
+    }
+
+    qemu_register_reset(escc2_reset, controller);
+    escc2_reset(controller);
+}
+
+const MemoryRegionOps escc2_mem_ops = {
+    .read = escc2_mem_read,
+    .write = escc2_mem_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void escc2_isa_realize(DeviceState *dev, Error **errp)
+{
+    ESCC2ISAState *isa = ESCC2_ISA(dev);
+    ESCC2State *controller = &isa->controller;
+
+    if (isa->iobase == -1) {
+        error_setg(errp, "Base address must be provided.");
+        return;
+    }
+
+    object_property_set_bool(OBJECT(controller), true, "realized", errp);
+    if (*errp) {
+        return;
+    }
+
+    memory_region_init_io(&controller->io, OBJECT(dev), &escc2_mem_ops,
+            controller, "escc2", CHANNEL_COUNT * CHANNEL_LENGTH);
+    isa_register_ioport(ISA_DEVICE(dev), &controller->io, isa->iobase);
+}
+
+static void escc2_unrealize(DeviceState *dev)
+{
+    ESCC2State *controller = ESCC2(dev);
+    qemu_unregister_reset(escc2_reset, controller);
+}
+
+static void escc2_isa_instance_init(Object *o)
+{
+    ESCC2ISAState *self = ESCC2_ISA(o);
+    object_initialize_child(o, "escc2", &self->controller,
+            sizeof(self->controller), TYPE_ESCC2, &error_abort, NULL);
+    qdev_alias_all_properties(DEVICE(&self->controller), o);
+}
+
+static Property escc2_properties[] = {
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static Property escc2_isa_properties[] = {
+    DEFINE_PROP_UINT32("iobase", ESCC2ISAState, iobase, -1),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void escc2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->user_creatable = false;
+    dc->realize = escc2_realize;
+    dc->unrealize = escc2_unrealize;
+    device_class_set_props(dc, escc2_properties);
+}
+
+static void escc2_isa_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, escc2_isa_properties);
+    dc->realize = escc2_isa_realize;
+}
+
+static const TypeInfo escc2_info = {
+    .name = TYPE_ESCC2,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ESCC2State),
+    .class_init = escc2_class_init
+};
+
+static const TypeInfo escc2_isa_info = {
+    .name = TYPE_ESCC2_ISA,
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ESCC2ISAState),
+    .instance_init = escc2_isa_instance_init,
+    .class_init = escc2_isa_class_init
+};
+
+static void escc2_types(void)
+{
+    type_register_static(&escc2_info);
+    type_register_static(&escc2_isa_info);
+}
+
+type_init(escc2_types);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index d20eafd56f..65c176f582 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -56,6 +56,10 @@ escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x"
 escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%01x"
 
+# escc2.c
+escc2_mem_read(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
+escc2_mem_write(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
+
 # pl011.c
 pl011_irq_state(int level) "irq state %d"
 pl011_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
diff --git a/include/hw/char/escc2.h b/include/hw/char/escc2.h
new file mode 100644
index 0000000000..ca2e34da3f
--- /dev/null
+++ b/include/hw/char/escc2.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Enhanced Serial Communication Controller (ESCC2 v3.2).
+ * Modelled according to the user manual (version 07.96).
+ *
+ * Copyright (C) 2020 Jasper Lowell
+ */
+#ifndef HW_ESCC2_H
+#define HW_ESCC2_H
+
+#define TYPE_ESCC2      "ESCC2"
+#define ESCC2(obj)      OBJECT_CHECK(ESCC2State, (obj), TYPE_ESCC2)
+
+#define TYPE_ESCC2_ISA  "ESCC2_ISA"
+#define ESCC2_ISA(obj)  OBJECT_CHECK(ESCC2ISAState, (obj), TYPE_ESCC2_ISA)
+
+#endif /* HW_ESCC2_H */
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/8] hw/char/escc2: Handle interrupt generation
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
  2020-06-17  8:23 ` [PATCH 1/8] hw/char/escc2: Add device Jasper Lowell
@ 2020-06-17  8:23 ` Jasper Lowell
  2020-06-17  8:23 ` [PATCH 3/8] hw/char/escc2: Add character device backend Jasper Lowell
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c      | 88 ++++++++++++++++++++++++++++++++++++++++++++
 hw/char/trace-events |  1 +
 2 files changed, 89 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 94528b8a4c..926346482f 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -8,6 +8,7 @@
 
 #include "qemu/osdep.h"
 #include "hw/char/escc2.h"
+#include "hw/irq.h"
 #include "hw/isa/isa.h"
 #include "hw/qdev-properties.h"
 #include "qapi/error.h"
@@ -55,6 +56,13 @@
 
 /* CCR0. */
 #define REGISTER_CCR0_OFFSET                    0x2c
+#define REGISTER_CCR0_PU                        0x80
+#define REGISTER_CCR0_MCE                       0x40
+#define REGISTER_CCR0_SC2                       0x10
+#define REGISTER_CCR0_SC1                       0x8
+#define REGISTER_CCR0_SC0                       0x4
+#define REGISTER_CCR0_SM1                       0x2
+#define REGISTER_CCR0_SM0                       0x1
 
 /* CCR1. */
 #define REGISTER_CCR1_OFFSET                    0x2d
@@ -94,12 +102,23 @@
 
 /* GIS. */
 #define REGISTER_GIS_OFFSET                     0x38
+#define REGISTER_GIS_PI                         0x80
+#define REGISTER_GIS_ISA1                       0x8
+#define REGISTER_GIS_ISA0                       0x4
+#define REGISTER_GIS_ISB1                       0x2
+#define REGISTER_GIS_ISB0                       0x1
 
 /* IVA. */
 #define REGISTER_IVA_OFFSET                     0x38
 
 /* IPC. */
 #define REGISTER_IPC_OFFSET                     0x39
+#define REGISTER_IPC_VIS                        0x80
+#define REGISTER_IPC_SLA1                       0x10
+#define REGISTER_IPC_SLA0                       0x8
+#define REGISTER_IPC_CASM                       0x4
+#define REGISTER_IPC_IC1                        0x2
+#define REGISTER_IPC_IC0                        0x1
 
 /* ISR0. */
 #define REGISTER_ISR0_OFFSET                    0x3a
@@ -207,6 +226,7 @@ struct ESCC2State {
     DeviceState parent;
 
     MemoryRegion io;
+    qemu_irq irq;
     ESCC2ChannelState channel[CHANNEL_COUNT];
 };
 
@@ -218,9 +238,62 @@ struct ESCC2State {
 typedef struct ESCC2ISAState {
     ISADevice parent;
     uint32_t iobase;
+    uint32_t irq;
     struct ESCC2State controller;
 } ESCC2ISAState;
 
+static void escc2_irq_update(ESCC2State *controller)
+{
+    bool power;
+    uint8_t gis;
+    ESCC2ChannelState *a, *b;
+
+    gis = 0;
+    a = CONTROLLER_CHANNEL_A(controller);
+    b = CONTROLLER_CHANNEL_B(controller);
+
+    /*
+     * Interrupts are not propagated to the CPU when in power-down mode. There
+     * is an exception for interrupts from the universal port.
+     */
+    power = REGISTER_READ(a, REGISTER_CCR0) & REGISTER_CCR0_PU;
+
+    if (REGISTER_READ(a, REGISTER_ISR0) & ~(REGISTER_READ(a, REGISTER_IMR0))) {
+        gis |= REGISTER_GIS_ISA0;
+    }
+    if (REGISTER_READ(a, REGISTER_ISR1) & ~(REGISTER_READ(a, REGISTER_IMR1))) {
+        gis |= REGISTER_GIS_ISA1;
+    }
+
+    if (REGISTER_READ(b, REGISTER_ISR0) & ~(REGISTER_READ(b, REGISTER_IMR0))) {
+        gis |= REGISTER_GIS_ISB0;
+    }
+    if (REGISTER_READ(b, REGISTER_ISR1) & ~(REGISTER_READ(b, REGISTER_IMR1))) {
+        gis |= REGISTER_GIS_ISB1;
+    }
+
+    if (REGISTER_READ(a, REGISTER_PIS) & ~(REGISTER_READ(a, REGISTER_PIM))) {
+        gis |= REGISTER_GIS_PI;
+        /*
+         * Ensure that interrupts are propagated even if the controller is in
+         * power-down mode.
+         */
+        power = true;
+    }
+
+    /* GIS is accessible from either channel and must be synchronised. */
+    REGISTER_WRITE(a, REGISTER_GIS, gis);
+    REGISTER_WRITE(b, REGISTER_GIS, gis);
+
+    if (gis && power) {
+        qemu_irq_raise(controller->irq);
+    } else {
+        qemu_irq_lower(controller->irq);
+    }
+
+    trace_escc2_irq_update(gis);
+}
+
 static void escc2_channel_reset(ESCC2ChannelState *channel)
 {
     unsigned int i;
@@ -320,15 +393,22 @@ static uint64_t escc2_mem_read(void *opaque, hwaddr addr, unsigned size)
         break;
     case REGISTER_ISR0_OFFSET:
         value = REGISTER_READ(channel, REGISTER_ISR0);
+        REGISTER_WRITE(channel, REGISTER_ISR0, 0);
+        escc2_irq_update(controller);
         break;
     case REGISTER_ISR1_OFFSET:
         value = REGISTER_READ(channel, REGISTER_ISR1);
+        REGISTER_WRITE(channel, REGISTER_ISR1, 0);
+        escc2_irq_update(controller);
         break;
     case REGISTER_PVR_OFFSET:
         value = REGISTER_READ(channel, REGISTER_PVR);
         break;
     case REGISTER_PIS_OFFSET:
         value = REGISTER_READ(channel, REGISTER_PIS);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_A(controller), REGISTER_PIS, 0);
+        REGISTER_WRITE(CONTROLLER_CHANNEL_B(controller), REGISTER_PIS, 0);
+        escc2_irq_update(controller);
         break;
     case REGISTER_PCR_OFFSET:
         value = REGISTER_READ(channel, REGISTER_PCR);
@@ -506,6 +586,13 @@ static void escc2_isa_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    if (isa->irq == -1) {
+        error_setg(errp, "IRQ must be provided.");
+        return;
+    }
+
+    isa_init_irq(ISA_DEVICE(dev), &controller->irq, isa->irq);
+
     object_property_set_bool(OBJECT(controller), true, "realized", errp);
     if (*errp) {
         return;
@@ -536,6 +623,7 @@ static Property escc2_properties[] = {
 
 static Property escc2_isa_properties[] = {
     DEFINE_PROP_UINT32("iobase", ESCC2ISAState, iobase, -1),
+    DEFINE_PROP_UINT32("irq", ESCC2ISAState, irq, -1),
     DEFINE_PROP_END_OF_LIST()
 };
 
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 65c176f582..b4f4f30815 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -57,6 +57,7 @@ escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%01x"
 
 # escc2.c
+escc2_irq_update(uint8_t gis) "value 0x%x"
 escc2_mem_read(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
 escc2_mem_write(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/8] hw/char/escc2: Add character device backend
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
  2020-06-17  8:23 ` [PATCH 1/8] hw/char/escc2: Add device Jasper Lowell
  2020-06-17  8:23 ` [PATCH 2/8] hw/char/escc2: Handle interrupt generation Jasper Lowell
@ 2020-06-17  8:23 ` Jasper Lowell
  2020-06-17  8:23 ` [PATCH 4/8] hw/char/escc2: Add clock generation Jasper Lowell
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 234 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 926346482f..e16049ce4d 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -7,6 +7,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "chardev/char-fe.h"
+#include "chardev/char-serial.h"
 #include "hw/char/escc2.h"
 #include "hw/irq.h"
 #include "hw/isa/isa.h"
@@ -17,6 +19,13 @@
 
 /* STAR. */
 #define REGISTER_STAR_OFFSET                    0x20
+#define REGISTER_STAR_XDOV                      0x80
+#define REGISTER_STAR_XFW                       0x40
+#define REGISTER_STAR_RFNE                      0x20
+#define REGISTER_STAR_FCS                       0x10
+#define REGISTER_STAR_TEC                       0x8
+#define REGISTER_STAR_CEC                       0x4
+#define REGISTER_STAR_CTS                       0x2
 
 /* CMDR. */
 #define REGISTER_CMDR_OFFSET                    0x20
@@ -38,9 +47,40 @@
 
 /* DAFO. */
 #define REGISTER_DAFO_OFFSET                    0x27
+#define REGISTER_DAFO_XBRK                      0x40
+#define REGISTER_DAFO_STOP                      0x20
+#define REGISTER_DAFO_PAR1                      0x10
+#define REGISTER_DAFO_PAR0                      0x8
+#define REGISTER_DAFO_PARE                      0x4
+#define REGISTER_DAFO_CHL1                      0x2
+#define REGISTER_DAFO_CHL0                      0x1
+
+#define REGISTER_DAFO_PAR_MASK \
+    (REGISTER_DAFO_PAR1 | REGISTER_DAFO_PAR0)
+#define REGISTER_DAFO_PAR_SPACE                 0x0
+#define REGISTER_DAFO_PAR_ODD                   (REGISTER_DAFO_PAR0)
+#define REGISTER_DAFO_PAR_EVEN                  (REGISTER_DAFO_PAR1)
+#define REGISTER_DAFO_PAR_MARK \
+    (REGISTER_DAFO_PAR1 | REGISTER_DAFO_PAR0)
+#define REGISTER_DAFO_CHL_MASK \
+    (REGISTER_DAFO_CHL1 | REGISTER_DAFO_CHL0)
+#define REGISTER_DAFO_CHL_CS8                   0x0
+#define REGISTER_DAFO_CHL_CS7                   (REGISTER_DAFO_CHL0)
+#define REGISTER_DAFO_CHL_CS6                   (REGISTER_DAFO_CHL1)
+#define REGISTER_DAFO_CHL_CS5 \
+    (REGISTER_DAFO_CHL1 | REGISTER_DAFO_CHL0)
 
 /* RFC. */
 #define REGISTER_RFC_OFFSET                     0x28
+#define REGISTER_RFC_DPS                        0x40
+#define REGISTER_RFC_DXS                        0x20
+#define REGISTER_RFC_RFDF                       0x10
+#define REGISTER_RFC_RFTH1                      0x8
+#define REGISTER_RFC_RFTH0                      0x4
+#define REGISTER_RFC_TCDE                       0x1
+
+#define REGISTER_RFC_RFTH_MASK \
+    (REGISTER_RFC_RFTH1 | REGISTER_RFC_RFTH0)
 
 /* RBCL. */
 #define REGISTER_RBCL_OFFSET                    0x2a
@@ -122,6 +162,14 @@
 
 /* ISR0. */
 #define REGISTER_ISR0_OFFSET                    0x3a
+#define REGISTER_ISR0_TCD                       0x80
+#define REGISTER_ISR0_TIME                      0x40
+#define REGISTER_ISR0_PERR                      0x20
+#define REGISTER_ISR0_FERR                      0x10
+#define REGISTER_ISR0_PLLA                      0x8
+#define REGISTER_ISR0_CDSC                      0x4
+#define REGISTER_ISR0_RFO                       0x2
+#define REGISTER_ISR0_RPF                       0x1
 
 /* IMR0. */
 #define REGISTER_IMR0_OFFSET                    0x3a
@@ -196,6 +244,8 @@ typedef struct ESCC2State ESCC2State;
 typedef struct ESCC2ChannelState {
     ESCC2State *controller;
 
+    CharBackend chardev;
+
     /*
      * The SAB 82532 ships with 64 byte FIFO queues for transmitting and
      * receiving but only 32 bytes are addressable.
@@ -294,6 +344,102 @@ static void escc2_irq_update(ESCC2State *controller)
     trace_escc2_irq_update(gis);
 }
 
+static void escc2_channel_irq_event(ESCC2ChannelState *channel,
+        uint8_t status_register, uint8_t event)
+{
+    /*
+     * Ensure that event does not have more than one bit set when calling this
+     * function.
+     */
+    uint8_t mask, tmp;
+
+    switch (status_register) {
+    case REGISTER_ISR0:
+        mask = REGISTER_READ(channel, REGISTER_IMR0);
+        break;
+    case REGISTER_ISR1:
+        mask = REGISTER_READ(channel, REGISTER_IMR1);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if ((event & ~(mask))
+            || (REGISTER_READ(channel, REGISTER_IPC) & REGISTER_IPC_VIS)) {
+        tmp = REGISTER_READ(channel, status_register);
+        tmp |= event;
+        REGISTER_WRITE(channel, status_register, tmp);
+    }
+
+    if (event & ~(mask)) {
+        escc2_irq_update(channel->controller);
+    }
+}
+
+static void escc2_channel_parameters_update(ESCC2ChannelState *channel)
+{
+    uint8_t dafo;
+    QEMUSerialSetParams ssp;
+
+    if (!qemu_chr_fe_backend_connected(&channel->chardev)) {
+        return;
+    }
+
+    /* Check if parity is enabled. */
+    dafo = REGISTER_READ(channel, REGISTER_DAFO);
+    if (dafo & REGISTER_DAFO_PARE) {
+        /* Determine the parity. */
+        switch (dafo & REGISTER_DAFO_PAR_MASK) {
+        case REGISTER_DAFO_PAR_SPACE:
+        case REGISTER_DAFO_PAR_MARK:
+            /*
+             * XXX: QEMU doesn't support stick parity yet. Silently fail and
+             * fall to the next case.
+             */
+        case REGISTER_DAFO_PAR_ODD:
+            ssp.parity = 'O';
+            break;
+        case REGISTER_DAFO_PAR_EVEN:
+            ssp.parity = 'E';
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    } else {
+        ssp.parity = 'N';
+    }
+
+    /* Determine the number of data bits. */
+    switch (dafo & REGISTER_DAFO_CHL_MASK) {
+    case REGISTER_DAFO_CHL_CS8:
+        ssp.data_bits = 8;
+        break;
+    case REGISTER_DAFO_CHL_CS7:
+        ssp.data_bits = 7;
+        break;
+    case REGISTER_DAFO_CHL_CS6:
+        ssp.data_bits = 6;
+        break;
+    case REGISTER_DAFO_CHL_CS5:
+        ssp.data_bits = 5;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    /* Determine the number of stop bits. */
+    if (dafo & REGISTER_DAFO_STOP) {
+        ssp.stop_bits = 2;
+    } else {
+        ssp.stop_bits = 1;
+    }
+
+    /* XXX */
+    ssp.speed = 0;
+
+    qemu_chr_fe_ioctl(&channel->chardev, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+}
+
 static void escc2_channel_reset(ESCC2ChannelState *channel)
 {
     unsigned int i;
@@ -469,6 +615,7 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         break;
     case REGISTER_DAFO_OFFSET:
         REGISTER_WRITE(channel, REGISTER_DAFO, value);
+        escc2_channel_parameters_update(channel);
         break;
     case REGISTER_RFC_OFFSET:
         REGISTER_WRITE(channel, REGISTER_RFC, value);
@@ -484,6 +631,7 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         break;
     case REGISTER_CCR1_OFFSET:
         REGISTER_WRITE(channel, REGISTER_CCR1, value);
+        escc2_channel_parameters_update(channel);
         break;
     case REGISTER_CCR2_OFFSET:
         REGISTER_WRITE(channel, REGISTER_CCR2, value);
@@ -505,9 +653,11 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         break;
     case REGISTER_BGR_OFFSET:
         REGISTER_WRITE(channel, REGISTER_BGR, value);
+        escc2_channel_parameters_update(channel);
         break;
     case REGISTER_TIC_OFFSET:
         REGISTER_WRITE(channel, REGISTER_TIC, value);
+        qemu_chr_fe_write_all(&channel->chardev, (uint8_t *)&value, 1);
         break;
     case REGISTER_MXN_OFFSET:
         REGISTER_WRITE(channel, REGISTER_MXN, value);
@@ -542,6 +692,7 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         break;
     case REGISTER_CCR4_OFFSET:
         REGISTER_WRITE(channel, REGISTER_CCR4, value);
+        escc2_channel_parameters_update(channel);
         break;
     default:
         /* Registers do not exhaustively cover the addressable region. */
@@ -551,6 +702,74 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
     trace_escc2_mem_write(CHANNEL_CHAR(channel), offset, value);
 }
 
+static unsigned int escc2_channel_rfifo_threshold(ESCC2ChannelState *channel)
+{
+    unsigned int threshold;
+
+    switch (REGISTER_READ(channel, REGISTER_RFC) & REGISTER_RFC_RFTH_MASK) {
+    case 0:
+        threshold = 1;
+        break;
+    case 1:
+        threshold = 4;
+        break;
+    case 2:
+        threshold = 16;
+        break;
+    case 3:
+        threshold = 32;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    return threshold;
+}
+
+static int escc2_channel_chardev_can_receive(void *opaque)
+{
+    uint8_t tmp;
+    ESCC2ChannelState *channel = opaque;
+    unsigned int threshold = escc2_channel_rfifo_threshold(channel);
+
+    tmp = REGISTER_READ(channel, REGISTER_RBCL);
+    if (threshold > tmp) {
+        return threshold - tmp;
+    } else {
+        return 0;
+    }
+}
+
+static void escc2_channel_chardev_receive(void *opaque, const uint8_t *buf,
+        int size)
+{
+    uint8_t tmp, rbcl;
+    unsigned int i, nbytes;
+    ESCC2ChannelState *channel = opaque;
+
+    /* Determine the number of characters that can be safely consumed. */
+    rbcl = REGISTER_READ(channel, REGISTER_RBCL);
+    if (rbcl + size > CHANNEL_FIFO_LENGTH) {
+        nbytes = CHANNEL_FIFO_LENGTH - rbcl;
+    } else {
+        nbytes = size;
+    }
+
+    /* Consume characters. */
+    for (i = 0; i < nbytes; i++) {
+        channel->fifo_receive[rbcl + i] = buf[i];
+    }
+    REGISTER_WRITE(channel, REGISTER_RBCL, rbcl + nbytes);
+
+    tmp = REGISTER_READ(channel, REGISTER_STAR);
+    tmp |= REGISTER_STAR_RFNE;
+    REGISTER_WRITE(channel, REGISTER_STAR, tmp);
+
+    if (escc2_channel_chardev_can_receive(channel) == 0) {
+        escc2_channel_irq_event(channel, REGISTER_ISR0, REGISTER_ISR0_RPF);
+    }
+}
+
 static void escc2_realize(DeviceState *dev, Error **errp)
 {
     unsigned int i;
@@ -560,6 +779,13 @@ static void escc2_realize(DeviceState *dev, Error **errp)
     for (i = 0; i < CHANNEL_COUNT; i++) {
         channel = &controller->channel[i];
         channel->controller = controller;
+
+        if (qemu_chr_fe_backend_connected(&channel->chardev)) {
+            qemu_chr_fe_set_handlers(&channel->chardev,
+                    escc2_channel_chardev_can_receive,
+                    escc2_channel_chardev_receive, NULL, NULL, channel, NULL,
+                    true);
+        }
     }
 
     qemu_register_reset(escc2_reset, controller);
@@ -605,7 +831,13 @@ static void escc2_isa_realize(DeviceState *dev, Error **errp)
 
 static void escc2_unrealize(DeviceState *dev)
 {
+    unsigned int i;
     ESCC2State *controller = ESCC2(dev);
+
+    for (i = 0; i < CHANNEL_COUNT; i++) {
+        qemu_chr_fe_deinit(&controller->channel[i].chardev, false);
+    }
+
     qemu_unregister_reset(escc2_reset, controller);
 }
 
@@ -618,6 +850,8 @@ static void escc2_isa_instance_init(Object *o)
 }
 
 static Property escc2_properties[] = {
+    DEFINE_PROP_CHR("chardevA", ESCC2State, channel[CHANNEL_A].chardev),
+    DEFINE_PROP_CHR("chardevB", ESCC2State, channel[CHANNEL_B].chardev),
     DEFINE_PROP_END_OF_LIST()
 };
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/8] hw/char/escc2: Add clock generation
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (2 preceding siblings ...)
  2020-06-17  8:23 ` [PATCH 3/8] hw/char/escc2: Add character device backend Jasper Lowell
@ 2020-06-17  8:23 ` Jasper Lowell
  2020-06-17  8:23 ` [PATCH 5/8] hw/char/escc2: Add Receiver Reset (RRES) command Jasper Lowell
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

Each channel on the controller has dedicated pins for providing receive
and transmit clock sources, a baud rate generator, and a DPLL.
Additionally, the controller has two pins, XTAL1 and XTAL2, that can be
used with a crystal and oscillator for providing a clock source.
Alternatively, XTAL1 can simply be used as a clock source. These
components are used individually or together according to register
configurations for generating the final receive and transmit clocks.

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 177 insertions(+), 2 deletions(-)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index e16049ce4d..059e033089 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -106,9 +106,31 @@
 
 /* CCR1. */
 #define REGISTER_CCR1_OFFSET                    0x2d
+#define REGISTER_CCR1_ODS                       0x10
+#define REGISTER_CCR1_BCR                       0x8
+#define REGISTER_CCR1_CM2                       0x4
+#define REGISTER_CCR1_CM1                       0x2
+#define REGISTER_CCR1_CM0                       0x1
+
+#define REGISTER_CCR1_CM_MASK \
+    (REGISTER_CCR1_CM2 | REGISTER_CCR1_CM1 | REGISTER_CCR1_CM0)
 
 /* CCR2. */
 #define REGISTER_CCR2_OFFSET                    0x2e
+#define REGISTER_CCR2_SOC1                      0x80
+#define REGISTER_CCR2_BR9                       0x80
+#define REGISTER_CCR2_SOC0                      0x40
+#define REGISTER_CCR2_BR8                       0x40
+#define REGISTER_CCR2_BDF                       0x20
+#define REGISTER_CCR2_XCS0                      0x20
+#define REGISTER_CCR2_SSEL                      0x10
+#define REGISTER_CCR2_RCS0                      0x10
+#define REGISTER_CCR2_TOE                       0x8
+#define REGISTER_CCR2_RWX                       0x4
+#define REGISTER_CCR2_DIV                       0x1
+
+#define REGISTER_CCR2_BR_MASK \
+    (REGISTER_CCR2_BR8 | REGISTER_CCR2_BR9)
 
 /* CCR3. */
 #define REGISTER_CCR3_OFFSET                    0x2f
@@ -131,6 +153,9 @@
 /* BGR. */
 #define REGISTER_BGR_OFFSET                     0x34
 
+#define REGISTER_BGR_EN_MASK                    0x3f
+#define REGISTER_BGR_EM_MASK                    0xc0
+
 /* TIC. */
 #define REGISTER_TIC_OFFSET                     0x35
 
@@ -194,6 +219,10 @@
 
 /* CCR4. */
 #define REGISTER_CCR4_OFFSET                    0x3f
+#define REGISTER_CCR4_MCK4                      0x80
+#define REGISTER_CCR4_EBRG                      0x40
+#define REGISTER_CCR4_TST1                      0x20
+#define REGISTER_CCR4_ICD                       0x10
 
 enum {
     REGISTER_STAR = 0,
@@ -244,6 +273,14 @@ typedef struct ESCC2State ESCC2State;
 typedef struct ESCC2ChannelState {
     ESCC2State *controller;
 
+    /*
+     * Each channel has dedicated pins for providing receive and transmit clock
+     * sources. These dedicated pins are a subset of a larger set of selectable
+     * clock sources.
+     */
+    unsigned int rxclock;
+    unsigned int txclock;
+
     CharBackend chardev;
 
     /*
@@ -275,6 +312,14 @@ enum {
 struct ESCC2State {
     DeviceState parent;
 
+    /*
+     * The controller has two pins: XTAL1 and XTAL2. These pins can be used
+     * together with a crystal and oscillator to provide a clock source.
+     * Alternatively, XTAL1 can provide an externally generated clock source.
+     * These configurations are mutually exclusive.
+     */
+    unsigned int xtal;
+
     MemoryRegion io;
     qemu_irq irq;
     ESCC2ChannelState channel[CHANNEL_COUNT];
@@ -376,9 +421,130 @@ static void escc2_channel_irq_event(ESCC2ChannelState *channel,
     }
 }
 
+static float escc2_channel_baud_rate_generate(ESCC2ChannelState *channel,
+        unsigned int clock)
+{
+    /*
+     * Each channel has an independent baud rate generator. This baud rate
+     * generator can act as a clock source for receiving, transmitting, and/or
+     * for the DPLL.
+     */
+    int k, n, m;
+    uint8_t ccr2 = REGISTER_READ(channel, REGISTER_CCR2);
+    uint8_t bgr = REGISTER_READ(channel, REGISTER_BGR);
+
+    if (REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_BDF) {
+        /* The baud rate division factor k relies on BGR. */
+        if (REGISTER_READ(channel, REGISTER_CCR4) & REGISTER_CCR4_EBRG) {
+            /* Enhanced mode. */
+            n = bgr & REGISTER_BGR_EN_MASK;
+            m = ((ccr2 & REGISTER_CCR2_BR_MASK) >> 6)
+                | ((bgr & REGISTER_BGR_EM_MASK) >> 6);
+            k = (n + 1) * (2 * m);
+        } else {
+            /* Standard mode. */
+            n = ((ccr2 & REGISTER_CCR2_BR_MASK) << 2) | bgr;
+            k = (n + 1) * 2;
+        }
+    } else {
+        k = 1;
+    }
+
+    return (float) clock / (16 * k);
+}
+
+static void escc2_channel_io_speed(ESCC2ChannelState *channel, float *input,
+        float *output)
+{
+    /*
+     * The receive and transmit speed can be configured to leverage dedicated
+     * receive and transmit clock source pins, the channel independent baud rate
+     * generator, the DPLL for handling clock synchronisation, the onboard
+     * oscillator, and a designated master clock. Different combinations of
+     * these are selected by specifying the clock mode and submode.
+     *
+     * Note: The DPLL, to function correctly, requires a clock source with a
+     * frequency 16 times the nominal bit rate so that the DPLL can synchronise
+     * the clock with the input stream. When the DPLL is used, the frequency
+     * must be divided by 16.
+     */
+    unsigned int mode = REGISTER_READ(channel, REGISTER_CCR1)
+        & REGISTER_CCR1_CM_MASK;
+    unsigned int submode = REGISTER_READ(channel, REGISTER_CCR2)
+        & REGISTER_CCR2_SSEL;
+
+    /* Clock modes are numbered 0 through 7. */
+    switch (mode) {
+    case 0:
+        *input = channel->rxclock;
+        if (!submode) {
+            /* 0a. */
+            *output = channel->txclock;
+        } else {
+            /* 0b. */
+            *output = escc2_channel_baud_rate_generate(channel,
+                    channel->controller->xtal);
+        }
+        break;
+    case 1:
+        *input = channel->rxclock;
+        *output = *input;
+        break;
+    case 2:
+        *input = escc2_channel_baud_rate_generate(channel, channel->rxclock)
+            / 16;
+        if (!(REGISTER_READ(channel, REGISTER_CCR2)
+                    & REGISTER_CCR2_SSEL)) {
+            /* 2a. */
+            *output = channel->txclock;
+        } else {
+            /* 2b. */
+            *output = *input;
+        }
+        break;
+    case 3:
+        *input = escc2_channel_baud_rate_generate(channel, channel->rxclock);
+        if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+            /* 3a. */
+            *input /= 16;
+        }
+        *output = *input;
+        break;
+    case 4:
+        *input = channel->controller->xtal;
+        *output = *input;
+    case 5:
+        *input = channel->rxclock;
+        *output = *input;
+    case 6:
+        *input = escc2_channel_baud_rate_generate(channel,
+                channel->controller->xtal) / 16;
+        if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+            /* 6a. */
+            *output = channel->txclock;
+        } else {
+            /* 6b. */
+            *output = *input;
+        }
+        break;
+    case 7:
+        *input = escc2_channel_baud_rate_generate(channel,
+                channel->controller->xtal);
+        if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+            /* 7a. */
+            *input /= 16;
+        }
+        *output = *input;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
 static void escc2_channel_parameters_update(ESCC2ChannelState *channel)
 {
     uint8_t dafo;
+    float ispeed, ospeed;
     QEMUSerialSetParams ssp;
 
     if (!qemu_chr_fe_backend_connected(&channel->chardev)) {
@@ -434,8 +600,12 @@ static void escc2_channel_parameters_update(ESCC2ChannelState *channel)
         ssp.stop_bits = 1;
     }
 
-    /* XXX */
-    ssp.speed = 0;
+    /*
+     * XXX: QEMU doesn't support configurations with different input/output
+     * speeds yet so the input speed is used for both.
+     */
+    escc2_channel_io_speed(channel, &ispeed, &ospeed);
+    ssp.speed = ispeed;
 
     qemu_chr_fe_ioctl(&channel->chardev, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
@@ -852,6 +1022,11 @@ static void escc2_isa_instance_init(Object *o)
 static Property escc2_properties[] = {
     DEFINE_PROP_CHR("chardevA", ESCC2State, channel[CHANNEL_A].chardev),
     DEFINE_PROP_CHR("chardevB", ESCC2State, channel[CHANNEL_B].chardev),
+    DEFINE_PROP_UINT32("xtal", ESCC2State, xtal, 0),
+    DEFINE_PROP_UINT32("rxclockA", ESCC2State, channel[CHANNEL_A].rxclock, 0),
+    DEFINE_PROP_UINT32("txclockA", ESCC2State, channel[CHANNEL_A].txclock, 0),
+    DEFINE_PROP_UINT32("rxclockB", ESCC2State, channel[CHANNEL_B].rxclock, 0),
+    DEFINE_PROP_UINT32("txclockB", ESCC2State, channel[CHANNEL_B].txclock, 0),
     DEFINE_PROP_END_OF_LIST()
 };
 
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/8] hw/char/escc2: Add Receiver Reset (RRES) command
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (3 preceding siblings ...)
  2020-06-17  8:23 ` [PATCH 4/8] hw/char/escc2: Add clock generation Jasper Lowell
@ 2020-06-17  8:23 ` Jasper Lowell
  2020-06-17  8:24 ` [PATCH 6/8] hw/char/escc2: Add RFRD command Jasper Lowell
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

Commands are initiated by setting certain bits in the CMDR register. The
Receiver Reset (RRES) command clears the receiver FIFO (RFIFO).

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c      | 24 ++++++++++++++++++++++++
 hw/char/trace-events |  1 +
 2 files changed, 25 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 059e033089..5afb8aa6d9 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -29,6 +29,12 @@
 
 /* CMDR. */
 #define REGISTER_CMDR_OFFSET                    0x20
+#define REGISTER_CMDR_RMC                       0x80
+#define REGISTER_CMDR_RRES                      0x40
+#define REGISTER_CMDR_RFRD                      0x20
+#define REGISTER_CMDR_STI                       0x10
+#define REGISTER_CMDR_XF                        0x8
+#define REGISTER_CMDR_XRES                      0x1
 
 /* MODE. */
 #define REGISTER_MODE_OFFSET                    0x22
@@ -741,6 +747,23 @@ static uint64_t escc2_mem_read(void *opaque, hwaddr addr, unsigned size)
     return value;
 }
 
+static void escc2_channel_command(ESCC2ChannelState *channel)
+{
+    uint8_t tmp, command;
+
+    command = REGISTER_READ(channel, REGISTER_CMDR);
+    trace_escc2_channel_command(CHANNEL_CHAR(channel), command);
+
+    if (command & REGISTER_CMDR_RRES) {
+        memset(channel->fifo_receive, 0, sizeof(channel->fifo_receive));
+        REGISTER_WRITE(channel, REGISTER_RBCL, 0);
+
+        tmp = REGISTER_READ(channel, REGISTER_STAR);
+        tmp &= ~(REGISTER_STAR_RFNE);
+        REGISTER_WRITE(channel, REGISTER_STAR, tmp);
+    }
+}
+
 static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         unsigned size)
 {
@@ -767,6 +790,7 @@ static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
         break;
     case REGISTER_CMDR_OFFSET:
         REGISTER_WRITE(channel, REGISTER_CMDR, value);
+        escc2_channel_command(channel);
         break;
     case REGISTER_MODE_OFFSET:
         REGISTER_WRITE(channel, REGISTER_MODE, value);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index b4f4f30815..47b46b92c9 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -59,6 +59,7 @@ escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%0
 # escc2.c
 escc2_irq_update(uint8_t gis) "value 0x%x"
 escc2_mem_read(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
+escc2_channel_command(char channel, uint8_t command) "channel %c command 0x%x"
 escc2_mem_write(char channel, uint32_t addr, uint8_t value) "channel %c addr 0x%x value 0x%x"
 
 # pl011.c
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/8] hw/char/escc2: Add RFRD command
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (4 preceding siblings ...)
  2020-06-17  8:23 ` [PATCH 5/8] hw/char/escc2: Add Receiver Reset (RRES) command Jasper Lowell
@ 2020-06-17  8:24 ` Jasper Lowell
  2020-06-17  8:24 ` [PATCH 7/8] hw/char/escc2: Add Transmit Frame (XF) command Jasper Lowell
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

The Receive FIFO Read Enable command is used to request access to the
receive FIFO. When the command is finished, the controller will issue a
TCD interrupt and the number of available bytes will be available in tthe
RBCL register. Given that the visible receive FIFO window is used to
store characters as they come in, the only action that needs to be taken
is to raise the TCD interrupt (if this interrupt is enabled).

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 5afb8aa6d9..8198b7fec3 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -762,6 +762,10 @@ static void escc2_channel_command(ESCC2ChannelState *channel)
         tmp &= ~(REGISTER_STAR_RFNE);
         REGISTER_WRITE(channel, REGISTER_STAR, tmp);
     }
+
+    if (command & REGISTER_CMDR_RFRD) {
+        escc2_channel_irq_event(channel, REGISTER_ISR0, REGISTER_ISR0_TCD);
+    }
 }
 
 static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/8] hw/char/escc2: Add Transmit Frame (XF) command
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (5 preceding siblings ...)
  2020-06-17  8:24 ` [PATCH 6/8] hw/char/escc2: Add RFRD command Jasper Lowell
@ 2020-06-17  8:24 ` Jasper Lowell
  2020-06-17  8:24 ` [PATCH 8/8] hw/char/escc2: Add XRES command Jasper Lowell
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

The Transmit Frame (XF) command is an alternative to using the TIC
register for transmitting. This command allows the guest to transmit the
contents of the transmit FIFO rather than a single character.

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 8198b7fec3..3bacdfaa7c 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -207,6 +207,14 @@
 
 /* ISR1. */
 #define REGISTER_ISR1_OFFSET                    0x3b
+#define REGISTER_ISR1_BRK                       0x80
+#define REGISTER_ISR1_BRKT                      0x40
+#define REGISTER_ISR1_ALLS                      0x20
+#define REGISTER_ISR1_XOFF                      0x10
+#define REGISTER_ISR1_TIN                       0x8
+#define REGISTER_ISR1_CSC                       0x4
+#define REGISTER_ISR1_XON                       0x2
+#define REGISTER_ISR1_XPR                       0x1
 
 /* IMR1. */
 #define REGISTER_IMR1_OFFSET                    0x3b
@@ -749,6 +757,7 @@ static uint64_t escc2_mem_read(void *opaque, hwaddr addr, unsigned size)
 
 static void escc2_channel_command(ESCC2ChannelState *channel)
 {
+    unsigned int i;
     uint8_t tmp, command;
 
     command = REGISTER_READ(channel, REGISTER_CMDR);
@@ -766,6 +775,21 @@ static void escc2_channel_command(ESCC2ChannelState *channel)
     if (command & REGISTER_CMDR_RFRD) {
         escc2_channel_irq_event(channel, REGISTER_ISR0, REGISTER_ISR0_TCD);
     }
+
+    if (command & REGISTER_CMDR_XF) {
+        i = 0;
+        while (i < CHANNEL_FIFO_LENGTH && channel->fifo_transmit[i] != 0) {
+            i++;
+        }
+        qemu_chr_fe_write_all(&channel->chardev, channel->fifo_transmit, i);
+        escc2_channel_irq_event(channel, REGISTER_ISR1, REGISTER_ISR1_ALLS);
+
+        /*
+         * XFIFO is ready and ISR1_XPR should be generated. Fake the XRES
+         * command.
+         */
+        command &= REGISTER_CMDR_XRES;
+    }
 }
 
 static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 8/8] hw/char/escc2: Add XRES command
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (6 preceding siblings ...)
  2020-06-17  8:24 ` [PATCH 7/8] hw/char/escc2: Add Transmit Frame (XF) command Jasper Lowell
@ 2020-06-17  8:24 ` Jasper Lowell
  2020-06-17  8:54 ` [PATCH 0/8] ESCC2 no-reply
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Jasper Lowell @ 2020-06-17  8:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: tony.nguyen, mark.cave-ayland, atar4qemu, Jasper Lowell

The Transmitter Reset (XRES) command is used for clearing the the
transmit FIFO of any data. When the controller has completed the
command, an XPR interrupt is generated (if this interrupt is enabled).

Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
 hw/char/escc2.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index 3bacdfaa7c..a40731b836 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -790,6 +790,11 @@ static void escc2_channel_command(ESCC2ChannelState *channel)
          */
         command &= REGISTER_CMDR_XRES;
     }
+
+    if (command & REGISTER_CMDR_XRES) {
+        memset(channel->fifo_transmit, 0, sizeof(channel->fifo_transmit));
+        escc2_channel_irq_event(channel, REGISTER_ISR1, REGISTER_ISR1_XPR);
+    }
 }
 
 static void escc2_mem_write(void *opaque, hwaddr addr, uint64_t value,
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] ESCC2
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (7 preceding siblings ...)
  2020-06-17  8:24 ` [PATCH 8/8] hw/char/escc2: Add XRES command Jasper Lowell
@ 2020-06-17  8:54 ` no-reply
  2020-06-17 13:33 ` Philippe Mathieu-Daudé
  2020-06-17 17:29 ` Artyom Tarasenko
  10 siblings, 0 replies; 12+ messages in thread
From: no-reply @ 2020-06-17  8:54 UTC (permalink / raw)
  To: jasper.lowell
  Cc: tony.nguyen, mark.cave-ayland, qemu-devel, atar4qemu, jasper.lowell

Patchew URL: https://patchew.org/QEMU/20200617082402.242631-1-jasper.lowell@bt.com/



Hi,

This series failed the asan build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.

=== TEST SCRIPT BEGIN ===
#!/bin/bash
export ARCH=x86_64
make docker-image-fedora V=1 NETWORK=1
time make docker-test-debug@fedora TARGET_LIST=x86_64-softmmu J=14 NETWORK=1
=== TEST SCRIPT END ===

  GEN     docs/interop/qemu-qmp-ref.html
  GEN     docs/interop/qemu-qmp-ref.txt
  GEN     docs/interop/qemu-qmp-ref.7
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  CC      qga/commands.o
  CC      qga/guest-agent-command-state.o
  CC      qga/main.o
---
  AR      libvhost-user.a
  GEN     docs/interop/qemu-ga-ref.html
  GEN     docs/interop/qemu-ga-ref.txt
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  GEN     docs/interop/qemu-ga-ref.7
  LINK    qemu-ga
  LINK    qemu-keymap
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  LINK    ivshmem-client
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  LINK    ivshmem-server
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  LINK    qemu-nbd
  AS      pc-bios/optionrom/multiboot.o
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  AS      pc-bios/optionrom/linuxboot.o
  CC      pc-bios/optionrom/linuxboot_dma.o
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  AS      pc-bios/optionrom/kvmvapic.o
  AS      pc-bios/optionrom/pvh.o
  LINK    qemu-storage-daemon
  CC      pc-bios/optionrom/pvh_main.o
  LINK    qemu-img
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  BUILD   pc-bios/optionrom/multiboot.img
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  BUILD   pc-bios/optionrom/linuxboot.img
  BUILD   pc-bios/optionrom/linuxboot_dma.img
  LINK    qemu-io
  BUILD   pc-bios/optionrom/kvmvapic.img
  BUILD   pc-bios/optionrom/multiboot.raw
  BUILD   pc-bios/optionrom/linuxboot.raw
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `  BUILD   pc-bios/optionrom/linuxboot_dma.raw
__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  LINK    qemu-edid
  BUILD   pc-bios/optionrom/kvmvapic.raw
  SIGN    pc-bios/optionrom/multiboot.bin
  SIGN    pc-bios/optionrom/linuxboot.bin
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  SIGN    pc-bios/optionrom/linuxboot_dma.bin
  LINK    fsdev/virtfs-proxy-helper
  SIGN    pc-bios/optionrom/kvmvapic.bin
  LINK    scsi/qemu-pr-helper
  LINK    qemu-bridge-helper
  LINK    virtiofsd
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  LINK    vhost-user-input
  BUILD   pc-bios/optionrom/pvh.img
  BUILD   pc-bios/optionrom/pvh.raw
  SIGN    pc-bios/optionrom/pvh.bin
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
/usr/bin/ld: /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors_vfork.S.o): warning: common of `__interception::real_vfork' overridden by definition from /usr/lib64/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.a(asan_interceptors.cpp.o)
  GEN     x86_64-softmmu/hmp-commands.h
  GEN     x86_64-softmmu/hmp-commands-info.h
  GEN     x86_64-softmmu/config-devices.h
---
  CC      x86_64-softmmu/hw/scsi/virtio-scsi.o
  CC      x86_64-softmmu/hw/scsi/virtio-scsi-dataplane.o
  CC      x86_64-softmmu/hw/scsi/vhost-scsi-common.o
/tmp/qemu-test/src/migration/ram.c:919:45: error: implicit conversion from 'unsigned long' to 'double' changes value from 18446744073709551615 to 18446744073709551616 [-Werror,-Wimplicit-int-float-conversion]
            xbzrle_counters.encoding_rate = UINT64_MAX;
                                          ~ ^~~~~~~~~~
/usr/include/stdint.h:130:23: note: expanded from macro 'UINT64_MAX'
---
18446744073709551615UL
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[1]: *** [/tmp/qemu-test/src/rules.mak:69: migration/ram.o] Error 1
make[1]: *** Waiting for unfinished jobs....
/tmp/qemu-test/src/fpu/softfloat.c:3365:13: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
    absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            !
/tmp/qemu-test/src/fpu/softfloat.c:3423:18: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
        absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven );
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 !
/tmp/qemu-test/src/fpu/softfloat.c:3483:18: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
        absZ0 &= ~(((uint64_t)(absZ1<<1) == 0) & roundNearestEven);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 !
/tmp/qemu-test/src/fpu/softfloat.c:3606:13: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
    zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            !
/tmp/qemu-test/src/fpu/softfloat.c:3760:13: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
    zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            !
/tmp/qemu-test/src/fpu/softfloat.c:3987:21: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
                    ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    !
/tmp/qemu-test/src/fpu/softfloat.c:4003:22: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
            zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                     !
/tmp/qemu-test/src/fpu/softfloat.c:4273:18: error: bitwise negation of a boolean expression; did you mean logical negation? [-Werror,-Wbool-operation]
        zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 !
8 errors generated.
make[1]: *** [/tmp/qemu-test/src/rules.mak:69: fpu/softfloat.o] Error 1
make: *** [Makefile:527: x86_64-softmmu/all] Error 2
Traceback (most recent call last):
  File "./tests/docker/docker.py", line 669, in <module>
    sys.exit(main())
---
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=8d05dab6690f47fa9c4a223cb750d7b8', '-u', '1001', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=x86_64-softmmu', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-ijl9vbi1/src/docker-src.2020-06-17-04.49.55.30222:/var/tmp/qemu:z,ro', 'qemu:fedora', '/var/tmp/qemu/run', 'test-debug']' returned non-zero exit status 2.
filter=--filter=label=com.qemu.instance.uuid=8d05dab6690f47fa9c4a223cb750d7b8
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-ijl9vbi1/src'
make: *** [docker-run-test-debug@fedora] Error 2

real    4m7.449s
user    0m8.702s


The full log is available at
http://patchew.org/logs/20200617082402.242631-1-jasper.lowell@bt.com/testing.asan/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] ESCC2
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (8 preceding siblings ...)
  2020-06-17  8:54 ` [PATCH 0/8] ESCC2 no-reply
@ 2020-06-17 13:33 ` Philippe Mathieu-Daudé
  2020-06-17 17:29 ` Artyom Tarasenko
  10 siblings, 0 replies; 12+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-06-17 13:33 UTC (permalink / raw)
  To: Jasper Lowell, qemu-devel
  Cc: tony.nguyen, mark.cave-ayland, Laurent Vivier,
	Marc-André Lureau, Paolo Bonzini, atar4qemu

Cc'ing chardev maintainers and Laurent.

On 6/17/20 10:23 AM, Jasper Lowell wrote:
> I've been working on improving Solaris 10 emulation for the SPARC64
> Sun4u architecture with the goal of a working shell. Currently, Solaris
> 10 boots with a number of errors before displaying the prompt of an
> otherwise unresponsive installer shell. It's been mentioned that this
> problem may not be isolated to Solaris 10 but may affect derivatives of
> OpenSolaris including illumos.
> 
> From what I can tell, Solaris 10 never attempts to use the 16550A UART
> for the serial console. The kernel will probe registers to identify the
> device but will not use it for receiving or transmitting. The kernel
> only prints to the console using the prom interface that OpenBIOS
> provides. It's difficult to ascertain what the problem is because there
> is no visibility into the kernel. The 16550A UART on the Ultra 5
> (Darwin), the machine that QEMU Sun4u is modelled against, is used for
> the keyboard/mouse (SuperIO) and is not traditionally used for the
> serial tty. Instead, the SAB 82532 ESCC2 is used to provide ttya and
> ttyb on this system. This patch exists to increment QEMU Sun4u towards
> being hardware faithful.
> 
> The SAB 82532 ESCC2 is complex because of the jungle of features that it
> provides. Linux and OpenBSD only use a small subset of features
> restricted to the ASYNC serial mode. The ASYNC serial mode is
> relatively simple to implement in isolation. I have made progress on a
> patch series that supports all serial modes, along with transitioning
> between them, but I have decided against submitting it. The serial
> controller appears to multiplex bit positions in registers across serial
> modes while preserving the bits themselves. This means that some 8-bit
> registers need to keep track of more than 8-bits of data and that the
> interpretation of the value the register holds depends on the selected
> serial mode. It's not ideal having a copy of each register for each
> serial mode because some bits are shared across some of the register
> modes. An added difficulty is that the manual doesn't document this
> behaviour well and its unclear what exactly happens when there is a
> transition in the selected serial mode. I've avoided depending on
> registers being uint8_t and have made use of macros so that the backend
> implementation of each register can be changed at a later date when
> supporting other serial modes. If I have the opportunity to test real
> hardware, or it becomes clear that HDLC/SDLC/BISYNC support is needed,
> I'll look at upstreaming the other changes that I have.
> 
> I have written a bare-bones patch for OpenBIOS that adds this device to
> the device tree. With that applied, Solaris identifies and attaches the
> device successfully but does not interact with it further - similar to
> the 16550A UART. I did notice, however, that Solaris 10 entered an
> interrupt routine for this device when the network card was being
> configured. I couldn't manage to provoke this behaviour for the 16550A
> so this might be some small success. I strongly suspect that the
> interrupt is a spurious interrupt caused by misconfiguration of the
> devices in the firmware but I have not investigated this further.
> 
> Solaris 10, judging from the OpenSolaris source code, determines
> stdin/stdout for the console by examining the stdin/stdout properties
> under /chosen in the device tree. Naturally, this is done with the prom
> interface. From what I can tell, to set these properties to the ESCC2
> node it's necessary to change stdin/stdout for OpenBIOS completely. This
> requires a device driver. I have made some progress on an OpenBIOS
> device driver for the ESCC2 but it's taking longer than expected to
> completely replace the 16550A and it's unlikely that I will have this
> finished soon. It's possible that Solaris 10 emulation for this platform
> will improve once that work is finished but it's unclear.
> 
> This is my first patch series for QEMU so it's possible that I've made
> mistakes in the contribution process - sorry in advance.
> 
> Jasper Lowell (8):
>   hw/char/escc2: Add device
>   hw/char/escc2: Handle interrupt generation
>   hw/char/escc2: Add character device backend
>   hw/char/escc2: Add clock generation
>   hw/char/escc2: Add Receiver Reset (RRES) command
>   hw/char/escc2: Add RFRD command
>   hw/char/escc2: Add Transmit Frame (XF) command
>   hw/char/escc2: Add XRES command
> 
>  hw/char/Kconfig         |    8 +
>  hw/char/Makefile.objs   |    1 +
>  hw/char/escc2.c         | 1135 +++++++++++++++++++++++++++++++++++++++
>  hw/char/trace-events    |    6 +
>  include/hw/char/escc2.h |   17 +
>  5 files changed, 1167 insertions(+)
>  create mode 100644 hw/char/escc2.c
>  create mode 100644 include/hw/char/escc2.h
> 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/8] ESCC2
  2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
                   ` (9 preceding siblings ...)
  2020-06-17 13:33 ` Philippe Mathieu-Daudé
@ 2020-06-17 17:29 ` Artyom Tarasenko
  10 siblings, 0 replies; 12+ messages in thread
From: Artyom Tarasenko @ 2020-06-17 17:29 UTC (permalink / raw)
  To: Jasper Lowell
  Cc: tony.nguyen, Mark Cave-Ayland, Laurent Vivier, qemu-devel,
	Marc-André Lureau, Paolo Bonzini,
	Philippe Mathieu-Daudé

On Wed, Jun 17, 2020 at 10:24 AM Jasper Lowell <jasper.lowell@bt.com> wrote:
>
> I've been working on improving Solaris 10 emulation for the SPARC64
> Sun4u architecture with the goal of a working shell. Currently, Solaris
> 10 boots with a number of errors before displaying the prompt of an
> otherwise unresponsive installer shell. It's been mentioned that this
> problem may not be isolated to Solaris 10 but may affect derivatives of
> OpenSolaris including illumos.
>
> From what I can tell, Solaris 10 never attempts to use the 16550A UART
> for the serial console. The kernel will probe registers to identify the
> device but will not use it for receiving or transmitting. The kernel
> only prints to the console using the prom interface that OpenBIOS
> provides. It's difficult to ascertain what the problem is because there
> is no visibility into the kernel. The 16550A UART on the Ultra 5
> (Darwin), the machine that QEMU Sun4u is modelled against, is used for
> the keyboard/mouse (SuperIO) and is not traditionally used for the
> serial tty. Instead, the SAB 82532 ESCC2 is used to provide ttya and
> ttyb on this system. This patch exists to increment QEMU Sun4u towards
> being hardware faithful.

Nice, thanks for sharing!

> The SAB 82532 ESCC2 is complex because of the jungle of features that it
> provides. Linux and OpenBSD only use a small subset of features
> restricted to the ASYNC serial mode. The ASYNC serial mode is
> relatively simple to implement in isolation. I have made progress on a
> patch series that supports all serial modes, along with transitioning
> between them, but I have decided against submitting it. The serial
> controller appears to multiplex bit positions in registers across serial
> modes while preserving the bits themselves. This means that some 8-bit
> registers need to keep track of more than 8-bits of data and that the
> interpretation of the value the register holds depends on the selected
> serial mode. It's not ideal having a copy of each register for each
> serial mode because some bits are shared across some of the register
> modes. An added difficulty is that the manual doesn't document this
> behaviour well and its unclear what exactly happens when there is a
> transition in the selected serial mode. I've avoided depending on
> registers being uint8_t and have made use of macros so that the backend
> implementation of each register can be changed at a later date when
> supporting other serial modes. If I have the opportunity to test real
> hardware, or it becomes clear that HDLC/SDLC/BISYNC support is needed,
> I'll look at upstreaming the other changes that I have.
>
> I have written a bare-bones patch for OpenBIOS that adds this device to
> the device tree. With that applied, Solaris identifies and attaches the
> device successfully but does not interact with it further - similar to
> the 16550A UART. I did notice, however, that Solaris 10 entered an
> interrupt routine for this device when the network card was being
> configured. I couldn't manage to provoke this behaviour for the 16550A
> so this might be some small success. I strongly suspect that the
> interrupt is a spurious interrupt caused by misconfiguration of the
> devices in the firmware but I have not investigated this further.
>
> Solaris 10, judging from the OpenSolaris source code, determines
> stdin/stdout for the console by examining the stdin/stdout properties
> under /chosen in the device tree. Naturally, this is done with the prom
> interface. From what I can tell, to set these properties to the ESCC2
> node it's necessary to change stdin/stdout for OpenBIOS completely. This
> requires a device driver. I have made some progress on an OpenBIOS
> device driver for the ESCC2 but it's taking longer than expected to
> completely replace the 16550A and it's unlikely that I will have this
> finished soon. It's possible that Solaris 10 emulation for this platform
> will improve once that work is finished but it's unclear.

Actually we may consider adding another sparc64 machine: "ultra5", and
maybe deprecate "sun4u" machine once OpenBIOS supports escc2. (But
maybe keep it as it's as long as it's used by NetBSD regression tests)

> This is my first patch series for QEMU so it's possible that I've made
> mistakes in the contribution process - sorry in advance.

Congratulations on the first patch!  It's a very good start.

> Jasper Lowell (8):
>   hw/char/escc2: Add device
>   hw/char/escc2: Handle interrupt generation
>   hw/char/escc2: Add character device backend
>   hw/char/escc2: Add clock generation
>   hw/char/escc2: Add Receiver Reset (RRES) command
>   hw/char/escc2: Add RFRD command
>   hw/char/escc2: Add Transmit Frame (XF) command
>   hw/char/escc2: Add XRES command
>
>  hw/char/Kconfig         |    8 +
>  hw/char/Makefile.objs   |    1 +
>  hw/char/escc2.c         | 1135 +++++++++++++++++++++++++++++++++++++++
>  hw/char/trace-events    |    6 +
>  include/hw/char/escc2.h |   17 +
>  5 files changed, 1167 insertions(+)
>  create mode 100644 hw/char/escc2.c
>  create mode 100644 include/hw/char/escc2.h
>
> --
> 2.26.2
>


-- 
Regards,
Artyom Tarasenko

SPARC and PPC PReP under qemu blog: http://tyom.blogspot.com/search/label/qemu


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2020-06-17 17:30 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-17  8:23 [PATCH 0/8] ESCC2 Jasper Lowell
2020-06-17  8:23 ` [PATCH 1/8] hw/char/escc2: Add device Jasper Lowell
2020-06-17  8:23 ` [PATCH 2/8] hw/char/escc2: Handle interrupt generation Jasper Lowell
2020-06-17  8:23 ` [PATCH 3/8] hw/char/escc2: Add character device backend Jasper Lowell
2020-06-17  8:23 ` [PATCH 4/8] hw/char/escc2: Add clock generation Jasper Lowell
2020-06-17  8:23 ` [PATCH 5/8] hw/char/escc2: Add Receiver Reset (RRES) command Jasper Lowell
2020-06-17  8:24 ` [PATCH 6/8] hw/char/escc2: Add RFRD command Jasper Lowell
2020-06-17  8:24 ` [PATCH 7/8] hw/char/escc2: Add Transmit Frame (XF) command Jasper Lowell
2020-06-17  8:24 ` [PATCH 8/8] hw/char/escc2: Add XRES command Jasper Lowell
2020-06-17  8:54 ` [PATCH 0/8] ESCC2 no-reply
2020-06-17 13:33 ` Philippe Mathieu-Daudé
2020-06-17 17:29 ` Artyom Tarasenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).