The current approach of using qemu_chr_fe_write() and ignoring the return values results in dropped characters [1]. Let's update the SiFive UART to use a async sifive_uart_xmit() function to transmit the characters and apply back pressure to the guest with the SIFIVE_UART_TXFIFO_FULL status. This should avoid dropped characters and more realisticly model the hardware. 1: https://gitlab.com/qemu-project/qemu/-/issues/2114 Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Tested-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20240910045419.1252277-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
		
			
				
	
	
		
			91 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SiFive UART interface
 | 
						|
 *
 | 
						|
 * Copyright (c) 2016 Stefan O'Rear
 | 
						|
 * Copyright (c) 2017 SiFive, Inc.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms and conditions of the GNU General Public License,
 | 
						|
 * version 2 or later, as published by the Free Software Foundation.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
						|
 * more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along with
 | 
						|
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef HW_SIFIVE_UART_H
 | 
						|
#define HW_SIFIVE_UART_H
 | 
						|
 | 
						|
#include "chardev/char-fe.h"
 | 
						|
#include "hw/qdev-properties.h"
 | 
						|
#include "hw/sysbus.h"
 | 
						|
#include "qom/object.h"
 | 
						|
#include "qemu/fifo8.h"
 | 
						|
 | 
						|
enum {
 | 
						|
    SIFIVE_UART_TXFIFO        = 0,
 | 
						|
    SIFIVE_UART_RXFIFO        = 4,
 | 
						|
    SIFIVE_UART_TXCTRL        = 8,
 | 
						|
    SIFIVE_UART_TXMARK        = 10,
 | 
						|
    SIFIVE_UART_RXCTRL        = 12,
 | 
						|
    SIFIVE_UART_RXMARK        = 14,
 | 
						|
    SIFIVE_UART_IE            = 16,
 | 
						|
    SIFIVE_UART_IP            = 20,
 | 
						|
    SIFIVE_UART_DIV           = 24,
 | 
						|
    SIFIVE_UART_MAX           = 32
 | 
						|
};
 | 
						|
 | 
						|
enum {
 | 
						|
    SIFIVE_UART_IE_TXWM       = 1, /* Transmit watermark interrupt enable */
 | 
						|
    SIFIVE_UART_IE_RXWM       = 2  /* Receive watermark interrupt enable */
 | 
						|
};
 | 
						|
 | 
						|
enum {
 | 
						|
    SIFIVE_UART_IP_TXWM       = 1, /* Transmit watermark interrupt pending */
 | 
						|
    SIFIVE_UART_IP_RXWM       = 2  /* Receive watermark interrupt pending */
 | 
						|
};
 | 
						|
 | 
						|
#define SIFIVE_UART_TXFIFO_FULL    0x80000000
 | 
						|
 | 
						|
#define SIFIVE_UART_GET_TXCNT(txctrl)   ((txctrl >> 16) & 0x7)
 | 
						|
#define SIFIVE_UART_GET_RXCNT(rxctrl)   ((rxctrl >> 16) & 0x7)
 | 
						|
 | 
						|
#define SIFIVE_UART_RX_FIFO_SIZE 8
 | 
						|
#define SIFIVE_UART_TX_FIFO_SIZE 8
 | 
						|
 | 
						|
#define TYPE_SIFIVE_UART "riscv.sifive.uart"
 | 
						|
OBJECT_DECLARE_SIMPLE_TYPE(SiFiveUARTState, SIFIVE_UART)
 | 
						|
 | 
						|
struct SiFiveUARTState {
 | 
						|
    /*< private >*/
 | 
						|
    SysBusDevice parent_obj;
 | 
						|
 | 
						|
    /*< public >*/
 | 
						|
    qemu_irq irq;
 | 
						|
    MemoryRegion mmio;
 | 
						|
    CharBackend chr;
 | 
						|
 | 
						|
    uint32_t txfifo;
 | 
						|
    uint32_t ie;
 | 
						|
    uint32_t ip;
 | 
						|
    uint32_t txctrl;
 | 
						|
    uint32_t rxctrl;
 | 
						|
    uint32_t div;
 | 
						|
 | 
						|
    uint8_t rx_fifo[SIFIVE_UART_RX_FIFO_SIZE];
 | 
						|
    uint8_t rx_fifo_len;
 | 
						|
 | 
						|
    Fifo8 tx_fifo;
 | 
						|
 | 
						|
    QEMUTimer *fifo_trigger_handle;
 | 
						|
};
 | 
						|
 | 
						|
SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
 | 
						|
    Chardev *chr, qemu_irq irq);
 | 
						|
 | 
						|
#endif
 |