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