blob: a2c1e32f713693a046ad54b78065ed8df165265a [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_TX_QUEUE_H_
#define SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_TX_QUEUE_H_
#include <lib/zx/event.h>
#include <ddktl/protocol/network/device.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include "data_structs.h"
#include "definitions.h"
namespace network::internal {
class DeviceInterface;
class Session;
class TxQueue {
public:
class SessionTransaction;
static zx_status_t Create(DeviceInterface* parent, std::unique_ptr<TxQueue>* out);
~TxQueue() = default;
// Reclaims all tx buffers currently held by the device implementation.
void Reclaim() __TA_REQUIRES(lock_) __TA_REQUIRES(buffers_lock_);
void Lock() __TA_ACQUIRE(lock_) __TA_ACQUIRE(buffers_lock_) {
lock_.Acquire();
buffers_lock_.Acquire();
}
void Unlock() __TA_RELEASE(lock_) __TA_RELEASE(buffers_lock_) {
buffers_lock_.Release();
lock_.Release();
}
// Helper class to handle Tx transactions from sessions.
class SessionTransaction {
public:
SessionTransaction(TxQueue* parent, Session* session) __TA_ACQUIRE(queue_->lock_)
__TA_ACQUIRE(queue_->buffers_lock_);
~SessionTransaction() __TA_RELEASE(queue_->lock_) __TA_RELEASE(queue_->buffers_lock_);
uint32_t available() const { return available_; }
bool overrun() const { return available_ == 0; }
tx_buffer_t* GetBuffer() __TA_REQUIRES(queue_->buffers_lock_);
void Push(uint16_t descriptor) __TA_REQUIRES(queue_->lock_)
__TA_REQUIRES(queue_->buffers_lock_);
private:
// pointer to queue over which transaction is opened, not owned.
TxQueue* queue_;
// pointer to session that opened the transaction, not owned.
Session* session_;
uint32_t available_;
uint32_t queued_;
DISALLOW_COPY_ASSIGN_AND_MOVE(SessionTransaction);
};
// Marks all buffers in tx as complete, returning them to their respective sessions.
void CompleteTxList(const tx_result_t* tx, size_t count) __TA_EXCLUDES(lock_);
private:
explicit TxQueue(DeviceInterface* parent) : parent_(parent) {}
struct InFlightBuffer {
InFlightBuffer() = default;
InFlightBuffer(Session* session, zx_status_t result, uint16_t descriptor_index)
: session(session), result(result), descriptor_index(descriptor_index) {}
Session* session;
zx_status_t result;
uint16_t descriptor_index;
};
// Adds the provided session:descriptor tuple to the queue and returns the buffer id.
uint32_t Enqueue(Session* session, uint16_t descriptor) __TA_REQUIRES(lock_);
// Marks the buffer with id as complete with the given status.
void MarkComplete(uint32_t id, zx_status_t status) __TA_REQUIRES(lock_);
// Returns all outstanding completed buffers to their respective sessions.
void ReturnBuffers() __TA_REQUIRES(lock_);
// pointer to parent device, not owned.
DeviceInterface* parent_;
fbl::Mutex lock_;
std::unique_ptr<RingQueue<uint32_t>> return_queue_ __TA_GUARDED(lock_);
std::unique_ptr<IndexedSlab<InFlightBuffer>> in_flight_ __TA_GUARDED(lock_);
// pre-allocated buffers that are locked to only allow a single session thread to send tx buffers
// to the device at once.
fbl::Mutex buffers_lock_ __TA_ACQUIRED_AFTER(lock_);
std::unique_ptr<tx_buffer_t[]> tx_buffers_ __TA_GUARDED(buffers_lock_);
std::unique_ptr<BufferParts[]> buffer_parts_ __TA_GUARDED(buffers_lock_);
DISALLOW_COPY_ASSIGN_AND_MOVE(TxQueue);
};
} // namespace network::internal
#endif // SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_TX_QUEUE_H_