more fifo

Change-Id: Ia5ed1eb7f7df0fe803d7afc101ad806cd20d4951
diff --git a/system/dev/usb/dwc3/dwc3-commands.cpp b/system/dev/usb/dwc3/dwc3-commands.cpp
index a1d2d8e..5315a34 100644
--- a/system/dev/usb/dwc3/dwc3-commands.cpp
+++ b/system/dev/usb/dwc3/dwc3-commands.cpp
@@ -9,6 +9,8 @@
 
 #include <stdio.h>
 
+namespace dwc3 {
+
 static void dwc3_ep_cmd(dwc3_t* dwc, unsigned ep_num, uint32_t command, uint32_t param0,
                         uint32_t param1, uint32_t param2, uint32_t flags) {
     auto* mmio = dwc3_mmio(dwc);
@@ -70,3 +72,5 @@
 void dwc3_cmd_ep_clear_stall(dwc3_t* dwc, unsigned ep_num) {
     dwc3_ep_cmd(dwc, ep_num, DEPCSTALL, 0, 0, 0, DEPCMD_CMDIOC);
 }
+
+} // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3-endpoints.cpp b/system/dev/usb/dwc3/dwc3-endpoints.cpp
index e9cbcdd..257db6c 100644
--- a/system/dev/usb/dwc3/dwc3-endpoints.cpp
+++ b/system/dev/usb/dwc3/dwc3-endpoints.cpp
@@ -18,9 +18,7 @@
 
 #define EP_FIFO_SIZE    PAGE_SIZE
 
-static zx_paddr_t dwc3_ep_trb_phys(dwc3_endpoint_t* ep, dwc3_trb_t* trb) {
-    return io_buffer_phys(&ep->fifo.buffer) + (trb - ep->fifo.first) * sizeof(*trb);
-}
+namespace dwc3 {
 
 static void dwc3_enable_ep(dwc3_t* dwc, unsigned ep_num, bool enable) {
     volatile void* reg = dwc3_mmio(dwc) + DALEPENA;
@@ -41,37 +39,14 @@
 zx_status_t dwc3_ep_fifo_init(dwc3_t* dwc, unsigned ep_num) {
     ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
-    dwc3_fifo_t* fifo = &ep->fifo;
 
-    static_assert(EP_FIFO_SIZE <= PAGE_SIZE, "");
-    zx_status_t status = io_buffer_init(&fifo->buffer, dwc->bti_handle.get(), EP_FIFO_SIZE,
-                                        IO_BUFFER_RW | IO_BUFFER_CONTIG);
-    if (status != ZX_OK) {
-        return status;
-    }
-
-    fifo->first = static_cast<dwc3_trb_t*>(io_buffer_virt(&fifo->buffer));
-    fifo->next = fifo->first;
-    fifo->current = nullptr;
-    fifo->last = fifo->first + (EP_FIFO_SIZE / sizeof(dwc3_trb_t)) - 1;
-
-    // set up link TRB pointing back to the start of the fifo
-    dwc3_trb_t* trb = fifo->last;
-    zx_paddr_t trb_phys = io_buffer_phys(&fifo->buffer);
-    trb->ptr_low = (uint32_t)trb_phys;
-    trb->ptr_high = (uint32_t)(trb_phys >> 32);
-    trb->status = 0;
-    trb->control = TRB_TRBCTL_LINK | TRB_HWO;
-    io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
-
-    return ZX_OK;
+    return ep->fifo.Init(EP_FIFO_SIZE, zx::unowned_handle(dwc->bti_handle));
 }
 
 void dwc3_ep_fifo_release(dwc3_t* dwc, unsigned ep_num) {
     ZX_DEBUG_ASSERT(ep_num < countof(dwc->eps));
     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
-
-    io_buffer_release(&ep->fifo.buffer);
+    ep->fifo.Release();
 }
 
 void dwc3_ep_start_transfer(dwc3_t* dwc, unsigned ep_num, unsigned type, zx_paddr_t buffer,
@@ -81,13 +56,7 @@
     // special case: EP0_OUT and EP0_IN use the same fifo
     dwc3_endpoint_t* ep = (ep_num == EP0_IN ? &dwc->eps[EP0_OUT] : &dwc->eps[ep_num]);
 
-    dwc3_trb_t* trb = ep->fifo.next++;
-    if (ep->fifo.next == ep->fifo.last) {
-        ep->fifo.next = ep->fifo.first;
-    }
-    if (ep->fifo.current == nullptr) {
-        ep->fifo.current = trb;
-    }
+    auto* trb = ep->fifo.Next(true);
 
     trb->ptr_low = (uint32_t)buffer;
     trb->ptr_high = (uint32_t)(buffer >> 32);
@@ -97,21 +66,18 @@
     } else {
         trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
     }
-    io_buffer_cache_flush(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
+    ep->fifo.FlushTrb(trb);
 
     if (send_zlp) {
-        dwc3_trb_t* zlp_trb = ep->fifo.next++;
-        if (ep->fifo.next == ep->fifo.last) {
-            ep->fifo.next = ep->fifo.first;
-        }
+        dwc3_trb_t* zlp_trb = ep->fifo.Next(false);
         zlp_trb->ptr_low = 0;
         zlp_trb->ptr_high = 0;
         zlp_trb->status = TRB_BUFSIZ(0);
         zlp_trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
-        io_buffer_cache_flush(&ep->fifo.buffer, (zlp_trb - ep->fifo.first) * sizeof(*trb), sizeof(*trb));
+        ep->fifo.FlushInvalidateTrb(zlp_trb);
     }
 
-    dwc3_cmd_ep_start_transfer(dwc, ep_num, dwc3_ep_trb_phys(ep, trb));
+    dwc3_cmd_ep_start_transfer(dwc, ep_num, ep->fifo.GetTrbPhys(trb));
 }
 
 static void dwc3_ep_queue_next_locked(dwc3_t* dwc, dwc3_endpoint_t* ep) {
@@ -255,16 +221,6 @@
     }
 }
 
-static void dwc_ep_read_trb(dwc3_endpoint_t* ep, dwc3_trb_t* trb, dwc3_trb_t* out_trb) {
-    if (trb >= ep->fifo.first && trb < ep->fifo.last) {
-        io_buffer_cache_flush_invalidate(&ep->fifo.buffer, (trb - ep->fifo.first) * sizeof(*trb),
-                                         sizeof(*trb));
-        memcpy((void *)out_trb, (void *)trb, sizeof(*trb));
-    } else {
-        zxlogf(ERROR, "dwc_ep_read_trb: bad trb\n");
-    }
-}
-
 void dwc3_ep_xfer_started(dwc3_t* dwc, unsigned ep_num, unsigned rsrc_id) {
     dwc3_endpoint_t* ep = &dwc->eps[ep_num];
     fbl::AutoLock lock(&ep->lock);
@@ -305,8 +261,7 @@
 
         if (req) {
             dwc3_trb_t  trb;
-            dwc_ep_read_trb(ep, ep->fifo.current, &trb);
-            ep->fifo.current = nullptr;
+            ep->fifo.ReadAndClearCurrentTrb(&trb);
             if (trb.control & TRB_HWO) {
                 zxlogf(ERROR, "TRB_HWO still set in dwc3_ep_xfer_complete\n");
             }
@@ -360,3 +315,5 @@
         usb_request_complete(req, reason, 0);
     }
 }
+
+} // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3-ep0.cpp b/system/dev/usb/dwc3/dwc3-ep0.cpp
index c431dd1..b9e712a 100644
--- a/system/dev/usb/dwc3/dwc3-ep0.cpp
+++ b/system/dev/usb/dwc3/dwc3-ep0.cpp
@@ -14,6 +14,8 @@
 
 #define EP0_LOCK(dwc)   (&(dwc)->eps[EP0_OUT].lock)
 
+namespace dwc3 {
+
 static void dwc3_queue_setup_locked(dwc3_t* dwc) {
     io_buffer_cache_flush_invalidate(&dwc->ep0_buffer, 0, sizeof(usb_setup_t));
     dwc3_ep_start_transfer(dwc, EP0_OUT, TRB_TRBCTL_SETUP, io_buffer_phys(&dwc->ep0_buffer),
@@ -215,3 +217,5 @@
         break;
     }
 }
+
+} // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3-events.cpp b/system/dev/usb/dwc3/dwc3-events.cpp
index 68286a6..c83ea11 100644
--- a/system/dev/usb/dwc3/dwc3-events.cpp
+++ b/system/dev/usb/dwc3/dwc3-events.cpp
@@ -11,6 +11,8 @@
 #include <stdio.h>
 #include <unistd.h>
 
+namespace dwc3 {
+
 static void dwc3_handle_ep_event(dwc3_t* dwc, uint32_t event) {
     uint32_t type = DEPEVT_TYPE(event);
     uint32_t ep_num = DEPEVT_PHYS_EP(event);
@@ -236,3 +238,5 @@
     dwc->irq_handle.destroy();
     thrd_join(dwc->irq_thread, nullptr);
 }
+
+} // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3-fifo.cpp b/system/dev/usb/dwc3/dwc3-fifo.cpp
new file mode 100644
index 0000000..d410039
--- /dev/null
+++ b/system/dev/usb/dwc3/dwc3-fifo.cpp
@@ -0,0 +1,66 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dwc3-fifo.h"
+
+#include <string.h>
+
+namespace dwc3 {
+
+
+zx_status_t Dwc3Fifo::Init(size_t buffer_size, zx::unowned_handle bti) {
+    ZX_DEBUG_ASSERT(buffer_size <= PAGE_SIZE);
+    auto status = io_buffer_init(&buffer_, bti->get(), buffer_size, IO_BUFFER_RW | IO_BUFFER_CONTIG);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    first_ = static_cast<dwc3_trb_t*>(io_buffer_virt(&buffer_));
+    next_ = first_;
+    current_ = nullptr;
+    last_ = first_ + (buffer_size / sizeof(dwc3_trb_t)) - 1;
+
+    // set up link TRB pointing back to the start of the fifo
+    dwc3_trb_t* trb = last_;
+    zx_paddr_t trb_phys = io_buffer_phys(&buffer_);
+    trb->ptr_low = (uint32_t)trb_phys;
+    trb->ptr_high = (uint32_t)(trb_phys >> 32);
+    trb->status = 0;
+    trb->control = TRB_TRBCTL_LINK | TRB_HWO;
+    io_buffer_cache_flush(&buffer_, (trb - first_) * sizeof(*trb), sizeof(*trb));
+
+    return ZX_OK;
+}
+
+void Dwc3Fifo::Release() {
+    io_buffer_release(&buffer_);
+    first_ = next_ = current_ = last_ = nullptr;
+}
+
+
+dwc3_trb_t* Dwc3Fifo::Next(bool set_current) {
+    dwc3_trb_t* trb = next_++;
+
+    if (next_ == last_) {
+        next_ = first_;
+    }
+    if (set_current && current_ == nullptr) {
+        current_ = trb;
+    }
+    return trb;
+}
+
+void Dwc3Fifo::ReadAndClearCurrentTrb(dwc3_trb_t* out_trb) {
+    ZX_DEBUG_ASSERT(current_ != nullptr);
+    volatile dwc3_trb_t* trb = current_;
+    current_ = nullptr;
+
+    FlushInvalidateTrb(trb);
+    out_trb->ptr_low = trb->ptr_low;
+    out_trb->ptr_high = trb->ptr_high;
+    out_trb->status = trb->status;
+    out_trb->control = trb->control;
+}
+
+} // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3-fifo.h b/system/dev/usb/dwc3/dwc3-fifo.h
index 4f6a512..2dc5365 100644
--- a/system/dev/usb/dwc3/dwc3-fifo.h
+++ b/system/dev/usb/dwc3/dwc3-fifo.h
@@ -5,6 +5,8 @@
 #pragma once
 
 #include <ddk/io-buffer.h>
+#include <fbl/macros.h>
+#include <lib/zx/handle.h>
 
 #include "dwc3-types.h"
 
@@ -12,15 +14,32 @@
 
 class Dwc3Fifo {
 public:
+    zx_status_t Init(size_t buffer_size, zx::unowned_handle bti);
+    void Release();
+
+    dwc3_trb_t* Next(bool set_current);
+    void ReadAndClearCurrentTrb(dwc3_trb_t* out_trb);
+
+    inline void FlushTrb(dwc3_trb_t* trb) {
+        io_buffer_cache_flush(&buffer_, (trb - first_) * sizeof(*trb), sizeof(*trb));
+    }
+
+    inline void FlushInvalidateTrb(dwc3_trb_t* trb) {
+        io_buffer_cache_flush_invalidate(&buffer_, (trb - first_) * sizeof(*trb), sizeof(*trb));
+    }
+
+    inline zx_paddr_t GetTrbPhys(dwc3_trb_t* trb) {
+        return io_buffer_phys(&buffer_) + (trb - first_) * sizeof(*trb);
+    }
 
 private:
     DISALLOW_COPY_ASSIGN_AND_MOVE(Dwc3Fifo);
 
-    io_buffer_t buffer;
-    dwc3_trb_t* first;      // first TRB in the fifo
-    dwc3_trb_t* next;       // next free TRB in the fifo
-    dwc3_trb_t* current;    // TRB for currently pending transaction
-    dwc3_trb_t* last;       // last TRB in the fifo (link TRB)
+    io_buffer_t buffer_;
+    dwc3_trb_t* first_;     // first TRB in the fifo
+    dwc3_trb_t* next_;      // next free TRB in the fifo
+    dwc3_trb_t* current_;   // TRB for currently pending transaction
+    dwc3_trb_t* last_;      // last TRB in the fifo (link TRB)
 };
 
 } // namespace dwc3
diff --git a/system/dev/usb/dwc3/dwc3.cpp b/system/dev/usb/dwc3/dwc3.cpp
index 30cfb0f..8543e50 100644
--- a/system/dev/usb/dwc3/dwc3.cpp
+++ b/system/dev/usb/dwc3/dwc3.cpp
@@ -20,6 +20,8 @@
 #include "dwc3-regs.h"
 #include "dwc3-types.h"
 
+namespace dwc3 {
+
 // MMIO indices
 enum {
     MMIO_USB3OTG,
@@ -454,7 +456,7 @@
     return device;
 }();
 
-zx_status_t dwc3_bind(void* ctx, zx_device_t* parent) {
+static zx_status_t dwc3_do_bind(zx_device_t* parent) {
     zxlogf(INFO, "dwc3_bind\n");
 
     auto* dwc = static_cast<dwc3_t*>(calloc(1, sizeof(dwc3_t)));
@@ -536,3 +538,9 @@
     dwc3_release(dwc);
     return status;
 }
+
+} // namespace dwc3
+
+zx_status_t dwc3_bind(void* ctx, zx_device_t* parent) {
+    return dwc3::dwc3_do_bind(parent);
+}
diff --git a/system/dev/usb/dwc3/dwc3.h b/system/dev/usb/dwc3/dwc3.h
index 7a371cd..6eb2a7c 100644
--- a/system/dev/usb/dwc3/dwc3.h
+++ b/system/dev/usb/dwc3/dwc3.h
@@ -43,6 +43,8 @@
 // converts a USB endpoint address to 0 - 31 index
 #define dwc3_ep_num(addr) ((((addr) & 0xF) << 1) | !!((addr) & USB_DIR_IN))
 
+namespace dwc3 {
+
 typedef enum {
     EP0_STATE_NONE,
     EP0_STATE_SETUP,            // Queued setup phase
@@ -54,15 +56,7 @@
 } dwc3_ep0_state;
 
 typedef struct {
-    io_buffer_t buffer;
-    dwc3_trb_t* first;      // first TRB in the fifo
-    dwc3_trb_t* next;       // next free TRB in the fifo
-    dwc3_trb_t* current;    // TRB for currently pending transaction
-    dwc3_trb_t* last;       // last TRB in the fifo (link TRB)
-} dwc3_fifo_t;
-
-typedef struct {
-    dwc3_fifo_t fifo;
+    Dwc3Fifo fifo;
     list_node_t queued_reqs;    // requests waiting to be processed
     usb_request_t* current_req; // request currently being processed
     unsigned rsrc_id;           // resource ID for current_req
@@ -173,8 +167,6 @@
 void dwc3_wait_bits(volatile uint32_t* ptr, uint32_t bits, uint32_t expected);
 void dwc3_print_status(dwc3_t* dwc);
 
-namespace dwc3 {
-
 class Dwc3;
 using Dwc3Type = ddk::Device<Dwc3>;
 
diff --git a/system/dev/usb/dwc3/rules.mk b/system/dev/usb/dwc3/rules.mk
index d9104ed..149034d 100644
--- a/system/dev/usb/dwc3/rules.mk
+++ b/system/dev/usb/dwc3/rules.mk
@@ -15,6 +15,7 @@
     $(LOCAL_DIR)/dwc3-endpoints.cpp \
     $(LOCAL_DIR)/dwc3-ep0.cpp \
     $(LOCAL_DIR)/dwc3-events.cpp \
+    $(LOCAL_DIR)/dwc3-fifo.cpp \
 
 MODULE_STATIC_LIBS := \
     system/ulib/ddk  	 \