| // Copyright (c) 2022 The Fuchsia Authors |
| // |
| // Permission to use, copy, modify, and/or distribute this software for any purpose with or without |
| // fee is hereby granted, provided that the above copyright notice and this permission notice |
| // appear in all copies. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS |
| // SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
| // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| // OF THIS SOFTWARE. |
| |
| #ifndef SRC_CONNECTIVITY_ETHERNET_DRIVERS_THIRD_PARTY_IGC_IGC_DRIVER_H_ |
| #define SRC_CONNECTIVITY_ETHERNET_DRIVERS_THIRD_PARTY_IGC_IGC_DRIVER_H_ |
| |
| #include <fidl/fuchsia.hardware.network.driver/cpp/driver/fidl.h> |
| #include <lib/async/cpp/irq.h> |
| #include <lib/driver/compat/cpp/device_server.h> |
| #include <lib/driver/component/cpp/driver_base.h> |
| #include <zircon/types.h> |
| |
| #include <mutex> |
| |
| #include "igc_api.h" |
| #include "src/connectivity/network/drivers/network-device/device/public/locks.h" |
| #include "src/lib/vmo_store/vmo_store.h" |
| |
| namespace ethernet { |
| namespace igc { |
| |
| using VmoStore = vmo_store::VmoStore<vmo_store::SlabStorage<uint32_t>>; |
| |
| // Internal Rx/Tx buffer metadata. |
| constexpr static size_t kEthRxBufCount = |
| 256; // Depth of Rx buffer, equal to the length of Rx desc ring buffer. |
| constexpr static size_t kEthRxBufSize = 2048; // Size of each Rx frame buffer. |
| constexpr static size_t kEthRxDescSize = 16; |
| |
| constexpr static size_t kEthTxDescRingCount = |
| 256; // The length of Tx desc ring buffer pool, should be greater than the actual tx buffer |
| // count, which left dummy spaces for ring buffer indexing. Both tx desc ring buffer pool |
| // length and actual tx buffer count should be multiples of 2. |
| |
| constexpr static size_t kEthTxBufCount = |
| 128; // Depth of Tx buffer that driver reports to network device. |
| constexpr static size_t kEthTxBufSize = 2048; // Size of each Tx frame buffer. |
| constexpr static size_t kEthTxDescSize = 16; |
| |
| constexpr static uint8_t kPortId = 1; |
| constexpr static size_t kEtherMtu = 1500; |
| constexpr static size_t kEtherAddrLen = 6; |
| |
| #define USE_NETDEV_DISPATCHER |
| |
| class IgcDriver final : public fdf::DriverBase, |
| public fdf::WireServer<fuchsia_hardware_network_driver::NetworkDeviceImpl>, |
| public fdf::WireServer<fuchsia_hardware_network_driver::NetworkPort>, |
| public fdf::WireServer<fuchsia_hardware_network_driver::MacAddr> { |
| public: |
| struct buffer_info; |
| struct adapter; |
| |
| explicit IgcDriver(fdf::DriverStartArgs start_args, |
| fdf::UnownedSynchronizedDispatcher driver_dispatcher); |
| ~IgcDriver(); |
| |
| // DriverBase implementation. |
| // Because there are Start methods in both NetworkDeviceImpl and DriverBase we need to override |
| // all of them to prevent error messages about hiding overloads. Make the asynchronous Start |
| // method behave just like the DriverBase implementation. |
| zx::result<> Start() override; |
| void Start(fdf::StartCompleter completer) override { DriverBase::Start(std::move(completer)); } |
| void PrepareStop(fdf::PrepareStopCompleter completer) override; |
| // Stop also exists in NetworkDeviceImpl and DriverBase, override it to avoid errors. |
| void Stop() override { DriverBase::Stop(); } |
| |
| // NetworkDeviceImpl implementation |
| void Init(fuchsia_hardware_network_driver::wire::NetworkDeviceImplInitRequest* request, |
| fdf::Arena& arena, InitCompleter::Sync& completer) override; |
| void Start(fdf::Arena& arena, StartCompleter::Sync& completer) override; |
| void Stop(fdf::Arena& arena, StopCompleter::Sync& completer) override; |
| void GetInfo( |
| fdf::Arena& arena, |
| fdf::WireServer<fuchsia_hardware_network_driver::NetworkDeviceImpl>::GetInfoCompleter::Sync& |
| completer) override; |
| void QueueTx(fuchsia_hardware_network_driver::wire::NetworkDeviceImplQueueTxRequest* request, |
| fdf::Arena& arena, QueueTxCompleter::Sync& completer) override; |
| void QueueRxSpace( |
| fuchsia_hardware_network_driver::wire::NetworkDeviceImplQueueRxSpaceRequest* request, |
| fdf::Arena& arena, QueueRxSpaceCompleter::Sync& completer) override; |
| void PrepareVmo( |
| fuchsia_hardware_network_driver::wire::NetworkDeviceImplPrepareVmoRequest* request, |
| fdf::Arena& arena, PrepareVmoCompleter::Sync& completer) override; |
| void ReleaseVmo( |
| fuchsia_hardware_network_driver::wire::NetworkDeviceImplReleaseVmoRequest* request, |
| fdf::Arena& arena, ReleaseVmoCompleter::Sync& completer) override; |
| void SetSnoop(fuchsia_hardware_network_driver::wire::NetworkDeviceImplSetSnoopRequest* request, |
| fdf::Arena& arena, SetSnoopCompleter::Sync& completer) override; |
| |
| // NetworkPort protocol implementation. |
| void GetInfo( |
| fdf::Arena& arena, |
| fdf::WireServer<fuchsia_hardware_network_driver::NetworkPort>::GetInfoCompleter::Sync& |
| completer) override; |
| void GetStatus(fdf::Arena& arena, GetStatusCompleter::Sync& completer) override; |
| void SetActive(fuchsia_hardware_network_driver::wire::NetworkPortSetActiveRequest* request, |
| fdf::Arena& arena, SetActiveCompleter::Sync& completer) override; |
| void GetMac(fdf::Arena& arena, GetMacCompleter::Sync& completer) override; |
| void Removed(fdf::Arena& arena, RemovedCompleter::Sync& completer) override; |
| |
| // MacAddr protocol: |
| void GetAddress(fdf::Arena& arena, GetAddressCompleter::Sync& completer) override; |
| void GetFeatures(fdf::Arena& arena, GetFeaturesCompleter::Sync& completer) override; |
| void SetMode(fuchsia_hardware_network_driver::wire::MacAddrSetModeRequest* request, |
| fdf::Arena& arena, SetModeCompleter::Sync& completer) override; |
| |
| buffer_info* RxBuffer() { return rx_buffers_; } |
| buffer_info* TxBuffer() { return tx_buffers_; } |
| std::shared_ptr<adapter> Adapter() { return adapter_; } |
| |
| // The return value indicates whether the online status has been changed. |
| bool OnlineStatusUpdate(); |
| |
| struct adapter { |
| struct igc_hw hw; |
| struct igc_osdep osdep; |
| mtx_t lock; |
| zx_handle_t irqh; |
| zx_handle_t btih; |
| |
| // Buffer to store tx/rx descriptor rings. |
| io_buffer_t desc_buffer; |
| |
| // tx/rx descriptor rings |
| struct igc_tx_desc* txdr; |
| union igc_adv_rx_desc* rxdr; |
| |
| // Base physical addresses for tx/rx rings. |
| // Store as 64-bit integer to match hw registers sizes. |
| uint64_t txd_phys; |
| uint64_t rxd_phys; |
| |
| // callback interface to attached ethernet layer |
| fdf::WireSharedClient<fuchsia_hardware_network_driver::NetworkDeviceIfc> netdev_ifc; |
| |
| uint32_t txh_ind; // Index of the head of awaiting(for the adapter to pick up) buffers in txdr. |
| uint32_t txt_ind; // Index of the tail of awaiting(for the adapter to pick up) buffers in txdr. |
| uint32_t txr_len; // Number of current entries in txdr. |
| uint32_t rxh_ind; // Index of the head of available buffers in rxdr. |
| uint32_t rxt_ind; // Index of the tail of available buffers in rxdr. |
| uint32_t rxr_len; // Number of current entries in rxdr. |
| // Protect the rx data path between the two operations: QueueRxSpace and IgcIrqThreadFunc. |
| std::mutex rx_lock; |
| // Protect the tx data path between the two operations: QueueTx and ReapTxBuffers. |
| std::mutex tx_lock; |
| fuchsia_hardware_pci::InterruptMode irq_mode; |
| |
| // Indicate a size for the arena so that we avoid re-allocation as much as possible. Don't use |
| // this arena for anything other than these RX buffers. |
| static constexpr size_t kArenaSize = fidl::MaxSizeInChannel< |
| fuchsia_hardware_network_driver::wire::NetworkDeviceIfcCompleteRxRequest, |
| fidl::MessageDirection::kSending>(); |
| fidl::Arena<kArenaSize> rx_buffer_arena; |
| |
| // Allocate a buffer array at half of the rx buffer ring size, and this limits the maximum |
| // number of packets that the driver passes up in one batch. |
| static constexpr size_t kRxBuffersPerBatch = kEthRxBufCount / 2; |
| fidl::VectorView<fuchsia_hardware_network_driver::wire::RxBuffer> buffers{rx_buffer_arena, |
| kRxBuffersPerBatch}; |
| }; |
| |
| // We store the buffer information for each rx_space_buffer in this struct, so that we can do |
| // CompleteRx based on these information. |
| struct buffer_info { |
| uint32_t buffer_id; |
| bool available; // Indicate whether this buffer info maps to a buffer passed down through |
| // RxSpace. |
| }; |
| |
| private: |
| void Shutdown(); |
| zx_status_t ConfigurePci(); |
| zx_status_t Initialize(); |
| zx_status_t AddNetworkDevice(); |
| bool IsValidEthernetAddr(uint8_t* addr); |
| void IdentifyHardware(); |
| zx_status_t AllocatePCIResources(); |
| zx_status_t InitBuffer(); |
| void InitTransmitUnit(); |
| void InitReceiveUnit(); |
| void IfSetPromisc(uint32_t flags); |
| void ReapTxBuffers(); |
| |
| void EnableInterrupt(); |
| void DisableInterrupt(); |
| void HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq_base, zx_status_t status, |
| const zx_packet_interrupt_t* interrupt); |
| |
| std::shared_ptr<struct adapter> adapter_{std::make_shared<struct adapter>()}; |
| async::IrqMethod<IgcDriver, &IgcDriver::HandleIrq> irq_handler_{this}; |
| |
| enum class State { Running, ShuttingDown, ShutDown }; |
| |
| std::atomic<State> state_ = State::Running; |
| |
| std::atomic<bool> started_ = false; |
| std::atomic<bool> online_ = false; |
| |
| // Lock for VMO changes. |
| network::SharedLock vmo_lock_; |
| |
| // Note: Extract Tx/Rx related variables to pcie_txrx.{h,cc}. |
| // The io_buffers created from the pre-allocated VMOs. |
| std::unique_ptr<VmoStore> vmo_store_ __TA_GUARDED(vmo_lock_); |
| |
| // An extension for rx decriptor. |
| buffer_info rx_buffers_[kEthRxBufCount]{}; |
| |
| // An extension for tx decriptor. |
| buffer_info tx_buffers_[kEthTxDescRingCount]{}; |
| |
| fdf::UnsynchronizedDispatcher netdev_dispatcher_; |
| |
| // Because NetworkDevice is currently DFv1 we need to have a compatibility server in place. |
| compat::SyncInitializedDeviceServer compat_server_; |
| fidl::WireClient<fuchsia_driver_framework::NodeController> controller_; |
| std::optional<fdf::ServerBindingRef<fuchsia_hardware_network_driver::NetworkDeviceImpl>> |
| netdev_binding_; |
| std::optional<fdf::ServerBindingRef<fuchsia_hardware_network_driver::NetworkPort>> port_binding_; |
| std::optional<fdf::ServerBindingRef<fuchsia_hardware_network_driver::MacAddr>> mac_binding_; |
| }; |
| |
| } // namespace igc |
| } // namespace ethernet |
| |
| #endif // SRC_CONNECTIVITY_ETHERNET_DRIVERS_THIRD_PARTY_IGC_IGC_DRIVER_H_ |