From patchwork Fri Jan 3 01:43:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Crosthwaite X-Patchwork-Id: 306388 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C159A2C008F for ; Fri, 3 Jan 2014 12:44:12 +1100 (EST) Received: from localhost ([::1]:47807 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vyto2-0006wl-Mn for incoming@patchwork.ozlabs.org; Thu, 02 Jan 2014 20:44:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42528) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vytna-0006n5-Fd for qemu-devel@nongnu.org; Thu, 02 Jan 2014 20:43:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VytnU-0007iC-3b for qemu-devel@nongnu.org; Thu, 02 Jan 2014 20:43:42 -0500 Received: from mail-pd0-f178.google.com ([209.85.192.178]:57199) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VytnT-0007hu-RF for qemu-devel@nongnu.org; Thu, 02 Jan 2014 20:43:36 -0500 Received: by mail-pd0-f178.google.com with SMTP id y10so14720010pdj.23 for ; Thu, 02 Jan 2014 17:43:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=57NE0STHyn9/0iSYJttjunfR21BZcotMU7C7CWFM9o4=; b=a3GpL8d1UBOeNYi9U8OGgbkS/ullxsk4cB/avzUHwsO+j/2GKBIQy53At35hL7UMGd cFRIxc3aI7kNHPLKPUP95W+Wp1Ra8ii415xpI/zuN76HhLLWcg5XotbZnLaJSnPq7HhE pvZKiWnbui0fLhzkG2EhALMrnR1Pe68KkA3Oc+kXq/V9Xgzc527r3w2ruiqlAYYdGznb N1hYRGN3CcQNQvngfcSd+4L6Ke4cdNfZmK9eYKYJNbCmBOc48tLGV9Qe70vakqUdoWhQ iWr6+QG05IWLCGqZ6qaM/3RtaDblJQS6x8Ok/PSdliKme23eVOzKuhBhkG965qDH/+d6 CHgw== X-Gm-Message-State: ALoCoQmu66QmIs8uJoD5B9XNN4kXVLuvooQ1SdHrWkf1lwEaJltJBhlDg28PYRIesYuKzmc2vlSh X-Received: by 10.68.133.229 with SMTP id pf5mr92450602pbb.115.1388713415078; Thu, 02 Jan 2014 17:43:35 -0800 (PST) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPSA id ju10sm104776784pbd.33.2014.01.02.17.43.33 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Thu, 02 Jan 2014 17:43:34 -0800 (PST) From: Peter Crosthwaite To: qemu-devel@nongnu.org Date: Thu, 2 Jan 2014 17:43:02 -0800 Message-Id: <0ac60aeb3e0907fdf6106f61f6358385ef845657.1388713158.git.peter.crosthwaite@xilinx.com> X-Mailer: git-send-email 1.8.5.2 In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.192.178 Cc: b.galvani@gmail.com, edgar.iglesias@gmail.com, pbonzini@redhat.com, peter.maydell@linaro.org Subject: [Qemu-devel] [RFC v1 2/2] util/fifo: Generalise for common integer widths X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add support for 16, 32 and 64 bit width FIFOs. The push and pop functions are patched to accept uint64_t always to support up to 64bit integer elements. The element width is set at creation time. The backing storage for all element types is still uint8_t regardless of element width so some save-load logic is needed to handle endianess issue WRT VMSD. Signed-off-by: Peter Crosthwaite --- hw/char/serial.c | 4 +-- hw/ssi/xilinx_spi.c | 4 +-- hw/ssi/xilinx_spips.c | 4 +-- include/qemu/fifo.h | 15 ++++++--- util/fifo.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 98 insertions(+), 20 deletions(-) diff --git a/hw/char/serial.c b/hw/char/serial.c index 9b43e36..cc71249 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -657,8 +657,8 @@ void serial_realize_core(SerialState *s, Error **errp) qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, serial_event, s); - fifo_create(&s->recv_fifo, UART_FIFO_LENGTH); - fifo_create(&s->xmit_fifo, UART_FIFO_LENGTH); + fifo_create(&s->recv_fifo, UART_FIFO_LENGTH, 8); + fifo_create(&s->xmit_fifo, UART_FIFO_LENGTH, 8); } void serial_exit_core(SerialState *s) diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index 8fe3072..cac666b 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -341,8 +341,8 @@ static int xilinx_spi_init(SysBusDevice *sbd) s->irqline = -1; - fifo_create(&s->tx_fifo, FIFO_CAPACITY); - fifo_create(&s->rx_fifo, FIFO_CAPACITY); + fifo_create(&s->tx_fifo, FIFO_CAPACITY, 8); + fifo_create(&s->rx_fifo, FIFO_CAPACITY, 8); return 0; } diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index c3d9c05..aeff06c 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -669,8 +669,8 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) s->irqline = -1; - fifo_create(&s->rx_fifo, xsc->rx_fifo_size); - fifo_create(&s->tx_fifo, xsc->tx_fifo_size); + fifo_create(&s->rx_fifo, xsc->rx_fifo_size, 8); + fifo_create(&s->tx_fifo, xsc->tx_fifo_size, 8); } static void xilinx_qspips_realize(DeviceState *dev, Error **errp) diff --git a/include/qemu/fifo.h b/include/qemu/fifo.h index e488387..a1737c3 100644 --- a/include/qemu/fifo.h +++ b/include/qemu/fifo.h @@ -5,8 +5,12 @@ typedef struct { /* All fields are private */ + int width; /* byte width each each element */ + uint32_t capacity; /* number of elements */ + uint8_t *data; - uint32_t capacity; + uint32_t buffer_size; + uint32_t head; uint32_t num; } Fifo; @@ -14,13 +18,14 @@ typedef struct { /** * fifo_create: * @fifo: struct Fifo to initialise with new FIFO - * @capacity: capacity of the newly created FIFO + * @capacity: capacity (number of elements) of the newly created FIFO + * @width: integer width of each element. Must be 8, 16, 32 or 64. * * Create a FIFO of the specified size. Clients should call fifo_destroy() * when finished using the fifo. The FIFO is initially empty. */ -void fifo_create(Fifo *fifo, uint32_t capacity); +void fifo_create(Fifo *fifo, uint32_t capacity, int width); /** * fifo_destroy: @@ -41,7 +46,7 @@ void fifo_destroy(Fifo *fifo); * Clients are responsible for checking for fullness using fifo_is_full(). */ -void fifo_push(Fifo *fifo, uint8_t data); +void fifo_push(Fifo *fifo, uint64_t data); /** * fifo_pop: @@ -53,7 +58,7 @@ void fifo_push(Fifo *fifo, uint8_t data); * Returns: The popped data value. */ -uint8_t fifo_pop(Fifo *fifo); +uint64_t fifo_pop(Fifo *fifo); /** * fifo_reset: diff --git a/util/fifo.c b/util/fifo.c index 1adaa11..33356ee 100644 --- a/util/fifo.c +++ b/util/fifo.c @@ -15,9 +15,11 @@ #include "qemu-common.h" #include "qemu/fifo.h" -void fifo_create(Fifo *fifo, uint32_t capacity) +void fifo_create(Fifo *fifo, uint32_t capacity, int width) { - fifo->data = g_new(uint8_t, capacity); + assert(width == 8 || width == 16 || width == 32 || width == 64); + fifo->width = width / 8; + fifo->data = g_new(uint8_t, capacity * fifo->width); fifo->capacity = capacity; fifo->head = 0; fifo->num = 0; @@ -28,26 +30,55 @@ void fifo_destroy(Fifo *fifo) g_free(fifo->data); } -void fifo_push(Fifo *fifo, uint8_t data) +void fifo_push(Fifo *fifo, uint64_t data) { + uint32_t next_idx = (fifo->head + fifo->num) % fifo->capacity; + if (fifo->num == fifo->capacity) { abort(); } - fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + switch (fifo->width) { + case(1): + ((uint8_t *)fifo->data)[next_idx] = data; + break; + case(2): + ((uint16_t *)fifo->data)[next_idx] = data; + break; + case(4): + ((uint32_t *)fifo->data)[next_idx] = data; + break; + case(8): + ((uint64_t *)fifo->data)[next_idx] = data; + break; + default: + abort(); + } fifo->num++; } -uint8_t fifo_pop(Fifo *fifo) +uint64_t fifo_pop(Fifo *fifo) { - uint8_t ret; + uint32_t next_idx; if (fifo->num == 0) { abort(); } - ret = fifo->data[fifo->head++]; + next_idx = fifo->head++; fifo->head %= fifo->capacity; fifo->num--; - return ret; + switch (fifo->width) { + case(1): + return ((uint8_t *)fifo->data)[next_idx]; + case(2): + return ((uint16_t *)fifo->data)[next_idx]; + case(4): + return ((uint32_t *)fifo->data)[next_idx]; + case(8): + return ((uint64_t *)fifo->data)[next_idx]; + default: + abort(); + return 0; /* unreachable */ + } } void fifo_reset(Fifo *fifo) @@ -65,13 +96,55 @@ bool fifo_is_full(Fifo *fifo) return (fifo->num == fifo->capacity); } +/* Always store buffer data in little (arbitrarily chosen) endian format to + * allow for migration to/from BE <-> LE hosts. + */ + +static inline void fifo_save_load_swap(Fifo *fifo) { +#ifdef HOST_WORDS_BIGENDIAN + int i; + uint16_t *d16 = (uint16_t *)fifo->data; + uint32_t *d32 = (uint32_t *)fifo->data; + uint64_t *d64 = (uint64_t *)fifo->data; + + for (i = 0; i < fifo->capacity; ++i) { + switch (fifo->width) { + case(1): + return; + case(2): + d16[i] = bswap16(d16[i]); + break; + case(4): + d32[i] = bswap32(d32[i]); + break; + case(8): + d64[i] = bswap64(d64[i]); + break; + default: + abort(); + } + } +#endif +} + +static void fifo_pre_save(void * opaque) { + fifo_save_load_swap((Fifo *)opaque); +} + +static int fifo_post_load(void *opaque, int version_id) { + fifo_save_load_swap((Fifo *)opaque); + return 0; +} + const VMStateDescription vmstate_fifo = { .name = "Fifo8", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, + .pre_save = fifo_pre_save, + .post_load = fifo_post_load, .fields = (VMStateField[]) { - VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, capacity), + VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, buffer_size), VMSTATE_UINT32(head, Fifo), VMSTATE_UINT32(num, Fifo), VMSTATE_END_OF_LIST()