From patchwork Tue Apr 16 00:27:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Crosthwaite X-Patchwork-Id: 236792 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E61422C00EF for ; Tue, 16 Apr 2013 10:32:58 +1000 (EST) Received: from localhost ([::1]:46027 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1URtpR-00079O-5w for incoming@patchwork.ozlabs.org; Mon, 15 Apr 2013 20:32:57 -0400 Received: from eggs.gnu.org ([208.118.235.92]:35052) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1URtmo-0003Nh-9c for qemu-devel@nongnu.org; Mon, 15 Apr 2013 20:30:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1URtmm-0001EE-Qx for qemu-devel@nongnu.org; Mon, 15 Apr 2013 20:30:14 -0400 Received: from mail-pd0-f169.google.com ([209.85.192.169]:54133) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1URtmm-0001E5-Gv for qemu-devel@nongnu.org; Mon, 15 Apr 2013 20:30:12 -0400 Received: by mail-pd0-f169.google.com with SMTP id 10so2795798pdc.0 for ; Mon, 15 Apr 2013 17:30:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=AfLSAmOTmUZI2zdAUS+eSU0vE5/keJL21LMixE1Gid8=; b=fld/gi8xQBbulHlOkKFngM7jI99ifDldbFSjSFAYHfPgkW/mCQCPN4im0nD8Fmu0qI 41KVj0iseiwv3jB2shc8/ZKQzvZu4yA3XbOE2qUhpDLEhHPLorG4VaTCI5yxBGtyf9dW J2S23EEm8Hm5CKacBQzQ82p3veStJNQTvcWyUOjn1QQy8xunehJZCz06bZdiQungwcnw djrmEvO4j/XfCqCtWosfN9cIVt1dMMbZ7BewwivNufP06Mt4M3+WDR68qfwemHUNc0l8 R6cc7oeU3l1WtedMD5/FgD8o1ANDmP8IbkwCGqYtDoxakVikHRan4kIhVNeVtdCSv5yl wUGw== X-Received: by 10.68.250.229 with SMTP id zf5mr23242pbc.148.1366072211754; Mon, 15 Apr 2013 17:30:11 -0700 (PDT) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPS id hp1sm136651pac.3.2013.04.15.17.30.09 (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Mon, 15 Apr 2013 17:30:10 -0700 (PDT) From: peter.crosthwaite@xilinx.com To: qemu-devel@nongnu.org Date: Tue, 16 Apr 2013 10:27:55 +1000 Message-Id: <2805449fede87e84546feaff28a2cb4dffcbf0e0.1366069170.git.peter.crosthwaite@xilinx.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: References: X-Gm-Message-State: ALoCoQmzpbBUhK1g8xkTGPYnSZMGIdRrIwHa8Sq7AeJq1jNvH/D9DG75o6Jttnc3DpgtT6Dq7pb7 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.192.169 Cc: edgar.iglesias@gmail.com Subject: [Qemu-devel] [PATCH v6 15/16] xilinx_axienet/dma: Implement rx path flow control 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 From: Peter Crosthwaite Implement flow control for the RX data path from xilinx_axienet->xilinx_axidma. On short return from axidma, then ethernet sets up the notify callback to resume transfer from where it left off. This also allows the ethernet to track whether there is an in progress transaction and return false from ethernet can_receive() as appropriate. If the DMA backs up or is disabled it waits for enablement. When the rx stream IO region is touched, the can_push() notify function is called if set. Signed-off-by: Peter Crosthwaite --- Fix notify control logic hw/dma/xilinx_axidma.c | 49 +++++++++++++++++++++++++++++++++++++++------- hw/net/xilinx_axienet.c | 28 ++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 80ce57f..a5bf102 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -117,6 +117,9 @@ struct XilinxAXIDMA { XilinxAXIDMAStreamSlave rx_data_dev; struct Stream streams[2]; + + StreamCanPushNotifyFn notify; + void *notify_opaque; }; /* @@ -315,16 +318,16 @@ static void stream_process_mem2s(struct Stream *s, } } -static void stream_process_s2mem(struct Stream *s, - unsigned char *buf, size_t len, uint32_t *app) +static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf, + size_t len, uint32_t *app) { uint32_t prev_d; unsigned int rxlen; - int pos = 0; + size_t pos = 0; int sof = 1; if (!stream_running(s) || stream_idle(s)) { - return; + return 0; } while (len) { @@ -369,6 +372,8 @@ static void stream_process_s2mem(struct Stream *s, break; } } + + return pos; } static void xilinx_axidma_reset(DeviceState *dev) @@ -381,19 +386,37 @@ static void xilinx_axidma_reset(DeviceState *dev) } } +static bool +xilinx_axidma_data_stream_can_push(StreamSlave *obj, + StreamCanPushNotifyFn notify, + void *notify_opaque) +{ + XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj); + struct Stream *s = &ds->dma->streams[1]; + + if (!stream_running(s) || stream_idle(s)) { + ds->dma->notify = notify; + ds->dma->notify_opaque = notify_opaque; + return false; + } + + return true; +} + static size_t xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app) { XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj); struct Stream *s = &ds->dma->streams[1]; + size_t ret; if (!app) { hw_error("No stream app data!\n"); } - stream_process_s2mem(s, buf, len, app); + ret = stream_process_s2mem(s, buf, len, app); stream_update_irq(s); - return len; + return ret; } static uint64_t axidma_read(void *opaque, hwaddr addr, @@ -481,6 +504,10 @@ static void axidma_write(void *opaque, hwaddr addr, s->regs[addr] = value; break; } + if (sid == 1 && d->notify) { + d->notify(d->notify_opaque); + d->notify = NULL; + } stream_update_irq(s); } @@ -558,11 +585,17 @@ static void axidma_class_init(ObjectClass *klass, void *data) dc->props = axidma_properties; } +static StreamSlaveClass xilinx_axidma_data_stream_class = { + .push = xilinx_axidma_data_stream_push, + .can_push = xilinx_axidma_data_stream_can_push, +}; + static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data) { StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); - ssc->push = data; + ssc->push = ((StreamSlaveClass *)data)->push; + ssc->can_push = ((StreamSlaveClass *)data)->can_push; } static const TypeInfo axidma_info = { @@ -578,7 +611,7 @@ static const TypeInfo xilinx_axidma_data_stream_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(struct XilinxAXIDMAStreamSlave), .class_init = xilinx_axidma_stream_class_init, - .class_data = xilinx_axidma_data_stream_push, + .class_data = &xilinx_axidma_data_stream_class, .interfaces = (InterfaceInfo[]) { { TYPE_STREAM_SLAVE }, { } diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 6d27546..544c3ec 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -383,6 +383,9 @@ struct XilinxAXIEnet { uint8_t *rxmem; + uint32_t *rxapp; + uint32_t rxsize; + uint32_t rxpos; }; static void axienet_rx_reset(XilinxAXIEnet *s) @@ -645,7 +648,7 @@ static int eth_can_rx(NetClientState *nc) XilinxAXIEnet *s = qemu_get_nic_opaque(nc); /* RX enabled? */ - return !axienet_rx_resetting(s) && axienet_rx_enabled(s); + return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s); } static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) @@ -663,6 +666,23 @@ static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) return match; } +static void axienet_eth_rx_notify(void *opaque) +{ + XilinxAXIEnet *s = XILINX_AXI_ENET(opaque); + + while (s->rxsize && stream_can_push(s->tx_dev, axienet_eth_rx_notify, s)) { + size_t ret = stream_push(s->tx_dev, (void *)s->rxmem + s->rxpos, + s->rxsize, s->rxapp); + s->rxsize -= ret; + s->rxpos += ret; + if (!s->rxsize) { + s->regs[R_IS] |= IS_RX_COMPLETE; + g_free(s->rxapp); + } + } + enet_update_irq(s); +} + static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { XilinxAXIEnet *s = qemu_get_nic_opaque(nc); @@ -800,9 +820,11 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) /* Good frame. */ app[2] |= 1 << 6; - stream_push(s->tx_dev, (void *)s->rxmem, size, app); + s->rxsize = size; + s->rxpos = 0; + s->rxapp = g_memdup(app, sizeof(app)); + axienet_eth_rx_notify(s); - s->regs[R_IS] |= IS_RX_COMPLETE; enet_update_irq(s); return size; }