// Copyright 2017 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 <fbl/auto_lock.h>

#include "src/devices/usb/drivers/dwc3/dwc3-regs.h"
#include "src/devices/usb/drivers/dwc3/dwc3.h"

namespace dwc3 {

zx_status_t Dwc3::Fifo::Init(zx::bti& bti) {
  if (buffer.is_valid()) {
    return ZX_ERR_BAD_STATE;
  }

  if (zx_status_t status = buffer.Init(bti.get(), Fifo::kFifoSize, IO_BUFFER_RW | IO_BUFFER_CONTIG);
      status != ZX_OK) {
    return status;
  }

  first = static_cast<dwc3_trb_t*>(buffer.virt());
  next = first;
  current = nullptr;
  last = first + (Fifo::kFifoSize / 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 = buffer.phys();
  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;
  buffer.CacheFlush((trb - first) * sizeof(*trb), sizeof(*trb));

  return ZX_OK;
}

void Dwc3::Fifo::Release() {
  buffer.release();
  first = next = current = last = nullptr;
}

void Dwc3::EpEnable(const Endpoint& ep, bool enable) {
  fbl::AutoLock lock(&lock_);
  auto* mmio = get_mmio();

  if (enable) {
    DALEPENA::Get().ReadFrom(mmio).EnableEp(ep.ep_num).WriteTo(mmio);
  } else {
    DALEPENA::Get().ReadFrom(mmio).DisableEp(ep.ep_num).WriteTo(mmio);
  }
}

void Dwc3::EpSetConfig(Endpoint& ep, bool enable) {
  zxlogf(DEBUG, "Dwc3::EpSetConfig %u", ep.ep_num);

  if (enable) {
    CmdEpSetConfig(ep, false);
    CmdEpTransferConfig(ep);
    EpEnable(ep, true);
  } else {
    EpEnable(ep, false);
  }
}

zx_status_t Dwc3::EpSetStall(Endpoint& ep, bool stall) {
  if (!ep.enabled) {
    return ZX_ERR_BAD_STATE;
  }

  if (stall && !ep.stalled) {
    CmdEpSetStall(ep);
  } else if (!stall && ep.stalled) {
    CmdEpClearStall(ep);
  }

  ep.stalled = stall;

  return ZX_OK;
}

void Dwc3::EpStartTransfer(Endpoint& ep, Fifo& fifo, uint32_t type, zx_paddr_t buffer,
                           size_t length, bool send_zlp) {
  zxlogf(SERIAL, "Dwc3::EpStartTransfer ep %u type %u length %zu", ep.ep_num, type, length);

  dwc3_trb_t* trb = fifo.next++;
  if (fifo.next == fifo.last) {
    fifo.next = fifo.first;
  }
  if (fifo.current == nullptr) {
    fifo.current = trb;
  }

  trb->ptr_low = static_cast<uint32_t>(buffer);
  trb->ptr_high = static_cast<uint32_t>(buffer >> 32);
  trb->status = TRB_BUFSIZ(static_cast<uint32_t>(length));
  if (send_zlp) {
    trb->control = type | TRB_HWO;
  } else {
    trb->control = type | TRB_LST | TRB_IOC | TRB_HWO;
  }
  fifo.buffer.CacheFlush((trb - fifo.first) * sizeof(*trb), sizeof(*trb));

  if (send_zlp) {
    dwc3_trb_t* zlp_trb = fifo.next++;
    if (fifo.next == fifo.last) {
      fifo.next = fifo.first;
    }
    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;
    fifo.buffer.CacheFlush((zlp_trb - fifo.first) * sizeof(*trb), sizeof(*trb));
  }

  CmdEpStartTransfer(ep, fifo.GetTrbPhys(trb));
}

void Dwc3::EpEndTransfers(Endpoint& ep, zx_status_t reason) {
  if (ep.current_req) {
    CmdEpEndTransfer(ep);

    usb_request_t* req = ep.current_req;
    ep.current_req = nullptr;
    req->response.status = reason;
    req->response.actual = 0;
    pending_completions_.push(Request{req, sizeof(*req)});
  }
  ep.got_not_ready = false;

  for (std::optional<Request> req = ep.queued_reqs.pop(); req; req = ep.queued_reqs.pop()) {
    req->request()->response.status = reason;
    req->request()->response.actual = 0;
    pending_completions_.push(std::move(*req));
  }
}

void Dwc3::EpReadTrb(Endpoint& ep, Fifo& fifo, const dwc3_trb_t* src, dwc3_trb_t* dst) {
  if (src >= fifo.first && src < fifo.last) {
    fifo.buffer.CacheFlushInvalidate((src - fifo.first) * sizeof(*src), sizeof(*src));
    memcpy(dst, src, sizeof(*dst));
  } else {
    zxlogf(ERROR, "bad trb");
  }
}

void Dwc3::UserEpQueueNext(UserEndpoint& uep) {
  Endpoint& ep = uep.ep;
  std::optional<Request> opt_req;

  if ((ep.current_req == nullptr) && ep.got_not_ready) {
    opt_req = ep.queued_reqs.pop();
  }

  if (opt_req.has_value()) {
    usb_request_t* req = ep.current_req = opt_req->take();
    ep.got_not_ready = false;

    if (ep.IsInput()) {
      usb_request_cache_flush(req, 0, req->header.length);
    } else {
      usb_request_cache_flush_invalidate(req, 0, req->header.length);
    }

    // TODO(voydanoff) scatter/gather support
    phys_iter_t iter;
    zx_paddr_t phys;
    usb_request_physmap(req, bti_.get());
    usb_request_phys_iter_init(&iter, req, zx_system_get_page_size());
    usb_request_phys_iter_next(&iter, &phys);
    bool send_zlp = req->header.send_zlp && ((req->header.length % ep.max_packet_size) == 0);
    EpStartTransfer(ep, uep.fifo, TRB_TRBCTL_NORMAL, phys, req->header.length, send_zlp);
  }
}

zx_status_t Dwc3::UserEpCancelAll(UserEndpoint& uep) {
  RequestQueue to_complete;
  {
    fbl::AutoLock lock(&uep.lock);
    to_complete = UserEpCancelAllLocked(uep);
  }

  // Now that we have dropped the lock, go ahead and complete all of the
  // requests we canceled.
  to_complete.CompleteAll(ZX_ERR_IO_NOT_PRESENT, 0);
  return ZX_OK;
}

Dwc3::RequestQueue Dwc3::UserEpCancelAllLocked(UserEndpoint& uep) {
  RequestQueue to_complete;

  // Move the endpoint's queue of requests into a local list so we can
  // complete the requests outside of the endpoint lock.
  to_complete = std::move(uep.ep.queued_reqs);

  // If there is currently a request in-flight, be sure to cancel its
  // transfer, and add the in-flight request to the local queue of requests to
  // complete.  Make sure we add this in-flight request to the _front_ of the
  // queue so that all requests are completed in the order that they were
  // queued.
  if (uep.ep.current_req != nullptr) {
    CmdEpEndTransfer(uep.ep);
    to_complete.push_next(Request{uep.ep.current_req, sizeof(*uep.ep.current_req)});
    uep.ep.current_req = nullptr;
  }

  // Return the list of requests back to the caller so they can complete them
  // once the enpoint's lock has finally been dropped.
  return to_complete;
}

void Dwc3::HandleEpTransferCompleteEvent(uint8_t ep_num) {
  if (is_ep0_num(ep_num)) {
    HandleEp0TransferCompleteEvent(ep_num);
    return;
  }

  usb_request_t* req = nullptr;
  {
    UserEndpoint* const uep = get_user_endpoint(ep_num);
    ZX_DEBUG_ASSERT(uep != nullptr);

    fbl::AutoLock lock{&uep->lock};
    std::swap(req, uep->ep.current_req);

    if (req) {
      dwc3_trb_t trb;
      EpReadTrb(uep->ep, uep->fifo, uep->fifo.current, &trb);
      uep->fifo.current = nullptr;

      if (trb.control & TRB_HWO) {
        zxlogf(ERROR, "TRB_HWO still set in dwc3_ep_xfer_complete");
      }

      req->response.actual = req->header.length - TRB_BUFSIZ(trb.status);
      req->response.status = ZX_OK;
    }
  }

  if (req) {
    pending_completions_.push(Request{req, sizeof(*req)});
  } else {
    zxlogf(ERROR, "no usb request found to complete!");
  }
}

void Dwc3::HandleEpTransferNotReadyEvent(uint8_t ep_num, uint32_t stage) {
  if (is_ep0_num(ep_num)) {
    HandleEp0TransferNotReadyEvent(ep_num, stage);
    return;
  }

  UserEndpoint* const uep = get_user_endpoint(ep_num);
  ZX_DEBUG_ASSERT(uep != nullptr);

  fbl::AutoLock lock(&uep->lock);
  uep->ep.got_not_ready = true;
  UserEpQueueNext(*uep);
}

void Dwc3::HandleEpTransferStartedEvent(uint8_t ep_num, uint32_t rsrc_id) {
  if (is_ep0_num(ep_num)) {
    fbl::AutoLock ep0_lock(&ep0_.lock);
    ((ep_num == kEp0Out) ? ep0_.out : ep0_.in).rsrc_id = rsrc_id;
  } else {
    UserEndpoint* const uep = get_user_endpoint(ep_num);
    ZX_DEBUG_ASSERT(uep != nullptr);

    fbl::AutoLock lock(&uep->lock);
    uep->ep.rsrc_id = rsrc_id;
  }
}

}  // namespace dwc3
