1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <atomic> 8 #include <ddk/device.h> 9 #include <ddk/protocol/test.h> 10 #include <ddktl/device.h> 11 #include <ddktl/mmio.h> 12 #include <ddktl/pdev.h> 13 #include <ddktl/protocol/ethernet.h> 14 #include <ddktl/protocol/ethernet/board.h> 15 #include <ddktl/protocol/ethernet/mac.h> 16 #include <fbl/mutex.h> 17 #include <fbl/unique_ptr.h> 18 #include <lib/sync/completion.h> 19 #include <lib/zx/interrupt.h> 20 #include <lib/zx/vmo.h> 21 #include <optional> 22 #include <threads.h> 23 #include <zircon/compiler.h> 24 #include <zircon/types.h> 25 26 #include "pinned-buffer.h" 27 28 // clang-format off 29 typedef volatile struct dw_mac_regs { 30 uint32_t conf; /*0 0x00 */ 31 uint32_t framefilt; /*1 0x04 */ 32 uint32_t hashtablehigh; /*2 0x08 */ 33 uint32_t hashtablelow; /*3 0x0c */ 34 uint32_t miiaddr; /*4 0x10 */ 35 uint32_t miidata; /*5 0x14 */ 36 uint32_t flowcontrol; /*6 0x18 */ 37 uint32_t vlantag; /*7 0x1c */ 38 uint32_t version; /*8 0x20 */ 39 uint32_t reserved_1[5]; /*9 - 13 */ 40 uint32_t intreg; /*14 0x38 */ 41 uint32_t intmask; /*15 0x3c */ 42 uint32_t macaddr0hi; /*16 0x40 */ 43 uint32_t macaddr0lo; /*17 0x44 */ 44 uint32_t macaddr1hi; /*18 0x48 */ 45 uint32_t macaddr1lo; /*19 0x4c */ 46 uint32_t reserved_2[34]; /*18 - 53 */ 47 uint32_t rgmiistatus; /*54 0xd8 */ 48 } __PACKED dw_mac_regs_t; 49 50 // Offset of DMA regs into dwmac register block 51 #define DW_DMA_BASE_OFFSET (0x1000) 52 53 typedef volatile struct dw_dma_regs { 54 uint32_t busmode; /*0 0x00 */ 55 uint32_t txpolldemand; /*1 0x04 */ 56 uint32_t rxpolldemand; /*2 0x08 */ 57 uint32_t rxdesclistaddr; /*3 0x0c */ 58 uint32_t txdesclistaddr; /*4 0x10 */ 59 uint32_t status; /*5 0x14 */ 60 uint32_t opmode; /*6 0x18 */ 61 uint32_t intenable; /*7 0x1c */ 62 uint32_t missedframes; /*8 0x20 */ 63 uint32_t rxwdt; /*9 0x24 */ 64 uint32_t axibusmode; /*10 0x28 */ 65 uint32_t axistatus; /*11 0x2c */ 66 uint32_t reserved[6]; 67 uint32_t currhosttxdesc; /*18 0x48 */ 68 uint32_t currhostrxdesc; /*19 0x4c */ 69 uint32_t currhosttxbuffaddr; /*20 0x50 */ 70 uint32_t currhostrxbuffaddr; /*21 0x54 */ 71 uint32_t hwfeature; /*22 0x58 */ 72 } __PACKED dw_dma_regs_t; 73 74 //DMA transaction descriptors 75 typedef volatile struct dw_dmadescr { 76 uint32_t txrx_status; 77 uint32_t dmamac_cntl; 78 uint32_t dmamac_addr; 79 uint32_t dmamac_next; 80 } __ALIGNED(64) dw_dmadescr_t; 81 // clang-format on 82 83 namespace eth { 84 85 class DWMacDevice : public ddk::Device<DWMacDevice, ddk::Unbindable>, 86 public ddk::EthmacProtocol<DWMacDevice, ddk::base_protocol>, 87 public ddk::EthMacProtocol<DWMacDevice> { 88 public: 89 DWMacDevice(zx_device_t* device); 90 91 static zx_status_t Create(zx_device_t* device); 92 93 void DdkRelease(); 94 void DdkUnbind(); 95 96 // ZX_PROTOCOL_ETHMAC ops. 97 zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* info); 98 void EthmacStop() __TA_EXCLUDES(lock_); 99 zx_status_t EthmacStart(const ethmac_ifc_t* ifc) __TA_EXCLUDES(lock_); 100 zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf) __TA_EXCLUDES(lock_); 101 zx_status_t EthmacSetParam(uint32_t param, int32_t value, const void* data, size_t data_size); 102 void EthmacGetBti(zx::bti* bti); 103 104 // ZX_PROTOCOL_ETH_MAC ops. 105 zx_status_t EthMacMdioWrite(uint32_t reg, uint32_t val); 106 zx_status_t EthMacMdioRead(uint32_t reg, uint32_t* val); 107 zx_status_t EthMacRegisterCallbacks(const eth_mac_callbacks_t* callbacks); 108 109 110 private: 111 112 zx_status_t InitBuffers(); 113 zx_status_t InitDevice(); 114 zx_status_t DeInitDevice() __TA_REQUIRES(lock_); 115 zx_status_t InitPdev(); 116 zx_status_t ShutDown() __TA_EXCLUDES(lock_); 117 118 void UpdateLinkStatus() __TA_REQUIRES(lock_); 119 void DumpRegisters(); 120 void ReleaseBuffers(); 121 void ProcRxBuffer(uint32_t int_status) __TA_EXCLUDES(lock_); 122 uint32_t DmaRxStatus(); 123 124 int Thread() __TA_EXCLUDES(lock_); 125 int WorkerThread(); 126 127 zx_status_t GetMAC(zx_device_t* dev); 128 129 //Number each of tx/rx transaction descriptors 130 static constexpr uint32_t kNumDesc = 32; 131 //Size of each transaction buffer 132 static constexpr uint32_t kTxnBufSize = 2048; 133 134 dw_dmadescr_t* tx_descriptors_ = nullptr; 135 dw_dmadescr_t* rx_descriptors_ = nullptr; 136 137 fbl::RefPtr<PinnedBuffer> txn_buffer_; 138 fbl::RefPtr<PinnedBuffer> desc_buffer_; 139 140 uint8_t* tx_buffer_ = nullptr; 141 uint32_t curr_tx_buf_ = 0; 142 uint8_t* rx_buffer_ = nullptr; 143 uint32_t curr_rx_buf_ = 0; 144 145 // designware mac options 146 uint32_t options_ = 0; 147 148 // ethermac fields 149 uint32_t features_ = 0; 150 uint32_t mtu_ = 0; 151 uint8_t mac_[MAC_ARRAY_LENGTH] = {}; 152 uint16_t mii_addr_ = 0; 153 154 zx::bti bti_; 155 zx::interrupt dma_irq_; 156 157 ddk::PDev pdev_; 158 ddk::EthBoardProtocolClient eth_board_; 159 160 std::optional<ddk::MmioBuffer> dwmac_regs_iobuff_; 161 162 dw_mac_regs_t* dwmac_regs_ = nullptr; 163 dw_dma_regs_t* dwdma_regs_ = nullptr; 164 165 fbl::Mutex lock_; 166 ddk::EthmacIfcClient ethmac_client_ __TA_GUARDED(lock_); 167 168 // Only accessed from Thread, so not locked. 169 bool online_ = false; 170 171 //statistics 172 uint32_t bus_errors_; 173 uint32_t tx_counter_ = 0; 174 uint32_t rx_packet_ = 0; 175 uint32_t loop_count_ = 0; 176 177 std::atomic<bool> running_; 178 179 thrd_t thread_; 180 thrd_t worker_thread_; 181 182 // PHY callbacks. 183 eth_mac_callbacks_t cbs_; 184 185 // Callbacks registered signal. 186 sync_completion_t cb_registered_signal_; 187 }; 188 189 } // namespace eth 190