| // Copyright 2024 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 ZIRCON_THIRD_PARTY_DEV_ETHERNET_E1000_FUCHSIA_H_ |
| #define ZIRCON_THIRD_PARTY_DEV_ETHERNET_E1000_FUCHSIA_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 "adapter.h" |
| #include "rings.h" |
| #include "src/connectivity/network/drivers/network-device/device/public/locks.h" |
| #include "src/lib/vmo_store/vmo_store.h" |
| |
| namespace e1000 { |
| |
| constexpr uint8_t kPortId = 0; |
| constexpr uint32_t kMaxMulticastFilters = 128; |
| |
| class DeviceBase; |
| struct adapter; |
| |
| class Driver : public fdf::DriverBase { |
| public: |
| Driver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher); |
| |
| const adapter* Adapter() const; |
| adapter* Adapter(); |
| |
| // DriverBase implementation. |
| zx::result<> Start() override; |
| void PrepareStop(fdf::PrepareStopCompleter completer) override; |
| |
| private: |
| friend class DeviceBase; |
| |
| std::unique_ptr<DeviceBase> device_; |
| }; |
| |
| // Provide access to DriverBase base class and allow storing the Device in a unique_ptr without |
| // specifying a template parameter. |
| class DeviceBase { |
| public: |
| explicit DeviceBase(Driver& driver) : driver_(driver) {} |
| virtual ~DeviceBase() = default; |
| |
| virtual zx::result<> Start() = 0; |
| virtual void PrepareStop(fdf::PrepareStopCompleter completer) = 0; |
| |
| virtual const adapter* Adapter() const = 0; |
| virtual adapter* Adapter() = 0; |
| |
| protected: |
| // Forward some calls to allow implementations access to fdf::DriverBase |
| fidl::ClientEnd<fuchsia_driver_framework::Node>& node() { return driver_.node(); } |
| const fidl::ClientEnd<fuchsia_driver_framework::Node>& node() const { return driver_.node(); } |
| const std::shared_ptr<fdf::Namespace>& incoming() const { return driver_.incoming(); } |
| std::shared_ptr<fdf::OutgoingDirectory>& outgoing() { return driver_.outgoing(); } |
| const fdf::UnownedSynchronizedDispatcher& driver_dispatcher() const { |
| return driver_.driver_dispatcher(); |
| } |
| async_dispatcher_t* dispatcher() const { return driver_.dispatcher(); } |
| |
| private: |
| Driver& driver_; |
| }; |
| |
| // There are potential assumptions in this code about rx descriptors all being the same size. If |
| // this were to change for any reason we should put some effort into investigating the implications. |
| static_assert(sizeof(e1000_rx_desc) == sizeof(e1000_rx_desc_extended) && |
| sizeof(e1000_rx_desc) == sizeof(e1000_adv_rx_desc), |
| "This code assumes that all RX descriptors are the same size."); |
| |
| // This is a templated implementation of the driver to allow different behavior for different |
| // generations of chips without resorting to virtual calls or function pointers. |
| template <typename RxDescriptor> |
| class Device : public DeviceBase, |
| 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: |
| Device(Driver& driver, std::unique_ptr<adapter>&& adapter, |
| std::unique_ptr<compat::SyncInitializedDeviceServer>&& compat_server); |
| |
| zx::result<> Start() override; |
| void PrepareStop(fdf::PrepareStopCompleter completer) override; |
| |
| const adapter* Adapter() const override { return adapter_.get(); } |
| adapter* Adapter() override { return adapter_.get(); } |
| |
| // 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 implementation. |
| 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; |
| |
| private: |
| zx::result<> AllocatePciResources(); |
| zx::result<> SetupDescriptors(); |
| zx::result<> AddNetworkDevice(); |
| void InitializeTransmitUnit() __TA_REQUIRES(adapter_->tx_mutex); |
| void InitializeReceiveUnit() __TA_REQUIRES(adapter_->rx_mutex); |
| void EnableInterrupts(); |
| void DisableInterrupts(); |
| |
| void HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq_base, zx_status_t status, |
| const zx_packet_interrupt_t* interrupt); |
| void FlushTxQueue() __TA_REQUIRES(adapter_->tx_mutex); |
| void FlushRxSpace() __TA_REQUIRES(adapter_->rx_mutex); |
| void UpdateOnlineStatus(bool reset); |
| void OnLinkStateChange(async_dispatcher_t*, async::TaskBase*, zx_status_t); |
| void SendOnlineStatus(bool online); |
| void SetMacFilterMode() __TA_REQUIRES(mac_filter_mutex_); |
| zx_paddr_t GetPhysicalAddress(const fuchsia_hardware_network_driver::wire::BufferRegion& region) |
| __TA_REQUIRES_SHARED(vmo_lock_); |
| |
| std::unique_ptr<adapter> adapter_; |
| |
| std::atomic<bool> started_ = false; |
| std::atomic<bool> online_ = false; |
| |
| RxRing<kRxDepth, RxDescriptor> rx_ring_ __TA_GUARDED(adapter_->rx_mutex); |
| TxRing<kTxDepth> tx_ring_ __TA_GUARDED(adapter_->tx_mutex); |
| |
| fuchsia_hardware_network::wire::MacFilterMode mac_filter_mode_ __TA_GUARDED(mac_filter_mutex_) = |
| fuchsia_hardware_network::wire::MacFilterMode::kPromiscuous; |
| std::vector<uint8_t> mac_filters_ __TA_GUARDED(mac_filter_mutex_); |
| std::mutex mac_filter_mutex_; |
| |
| using VmoStore = vmo_store::VmoStore<vmo_store::SlabStorage<uint32_t>>; |
| std::unique_ptr<VmoStore> vmo_store_ __TA_GUARDED(vmo_lock_); |
| network::SharedLock vmo_lock_; |
| |
| // Because NetworkDevice is currently DFv1 we need to have a compatibility server in place. |
| std::unique_ptr<compat::SyncInitializedDeviceServer> compat_server_; |
| fidl::WireClient<fuchsia_driver_framework::NodeController> controller_; |
| fdf::UnsynchronizedDispatcher netdev_dispatcher_; |
| |
| // Keep these last so that they are destroyed first, canceling any pending calls to these methods |
| // before they can access other data members that are destroyed. |
| async::IrqMethod<Device, &Device::HandleIrq> irq_handler_{this}; |
| async::TaskMethod<Device<RxDescriptor>, &Device<RxDescriptor>::OnLinkStateChange> |
| on_link_state_change_task_{this}; |
| }; |
| |
| } // namespace e1000 |
| |
| #endif // ZIRCON_THIRD_PARTY_DEV_ETHERNET_E1000_FUCHSIA_H_ |