/* * EMAC driver for NVCom-02TEM-3U evaluation kit * * Copyright (c) 2020 Elvees (support@elvees.com) * Author: Dmitry Evtushenko * */ #ifndef __emac_h #define __emac_h #include #include //#include #include #ifdef CONFIG_MIPS #include #endif //CONFIG_MIPS #include "../common/fifo.h" ////////////////////////////////// DEFINES: ////////////////////////////////// #define USE_MULTI_MBUF //#define USE_RX_IN_IRQ //- unused now //#define USE_TX_IN_IRQ //- unused now //#define USE_EXT_IRQ_PHY_LINK //- использование внешнего прерывания от PHY, // для отслеживания состояния соединения #define CARD_NAME "mc_eth" #define CARD_VERSION "NVCOM-01" #define MODULE_NAME "mc_eth" #define DRIVER_VERSION "1.0" #define PROC_FILENAME "eth_stat" #define EMAC_DEV_NAME "emac" //- "EMAC" #define SPF_DRIVER_VER 1 #define ETH_MTU 1500 // Максимальный размер пакета #define ETH_HEADER_SIZE 14 // Размер заголовка пакета #define ETH_CRC_SIZE 4 // Размер CRC // return codes: #define RC_EMAC_SUCCESS 0 #define RC_EMAC_ERROR -1 // TX descriptor min/max quantity: #define EMAC_MIN_TX_DSC_QNT 10 #define EMAC_MAX_TX_DSC_QNT 30 // RX descriptor min/max quantity: #define EMAC_MIN_RX_DSC_QNT 10 #define EMAC_MAX_RX_DSC_QNT 60 // TX/RX default descriptor quantity: #define EMAC_DFLT_TX_DSC_QNT 30 //60 //15 //47 #define EMAC_DFLT_RX_DSC_QNT 60 //#define EMAC_TX_DMA_FIFO_SIZE 30 //60 //15 //47 //#define EMAC_RX_DMA_FIFO_SIZE 60 // DEBUG: //#define PRINT_SHORT_ENA #ifdef PRINT_SHORT_ENA #define EPRINT pr_info #else //!PRINT_SHORT_ENA: #define EPRINT print_empty #endif //!PRINT_SHORT_ENA #ifdef USE_EXT_IRQ_PHY_LINK #define IRQ_EXT_LINK_DFLT QSTR_IRQNO(3) #endif //USE_EXT_IRQ_PHY_LINK // текущее положение данных: enum emac_dma_data_state_e { EDDS_NONE, //- нет данных //EDDS_DMA, //- данные в буфере DMA //EDDS_DMA_FIFO, //- данные пересылаются между буферами DMA и FIFO //EDDS_FIFO_DMA = EDDS_DMA_FIFO, //- данные пересылаются между буферами FIFO и DMA EDDS_MEM, //- данные в буфере памяти EDDS_DMA_TO_FIFO, //- данные пересылаются DMA из памяти в FIFO (Tx сторона) EDDS_DMA_TO_MEM, //- данные пересылаются DMA из FIFO в память (Rx сторона) EDDS_FIFO, //- данные в FIFO контроллера EDDS_FIFO_PHY, //- данные пересылаются между FIFO и PHY EDDS_PHY, //- данные в PHY EDDS_ERROR //- что-то пошло не так ... }; #ifdef USE_MULTI_MBUF #define MAX_MMBUF_TX_SIZE 32768 // 16384 // 98304 //- 0x18000 #define MAX_MMBUF_RX_SIZE 98304 //- 0x18000 struct __attribute__((__packed__)) multi_mbuf_s { char *pbuf __attribute__((aligned(8))); // <- TODO dma_addr_t buf_phys; u32 sz_buf; char *pend; char *phead; char *ptail; }; typedef struct multi_mbuf_s multi_mbuf_t; extern bool mmbuf_init( multi_mbuf_t *pmb, u32 szmb); extern void mmbuf_destroy( multi_mbuf_t *pmb); static inline void mmbuf_reset( multi_mbuf_t *pmb) { pmb->phead = pmb->ptail = pmb->pbuf; } //extern void mmbuf_get_free_size( multi_mbuf_t *pmb, u32 *pszr, u32 *pszl); extern bool mmbuf_hold_mem( multi_mbuf_t *pmb, u32 szmem, char **ppmem); extern bool mmbuf_free_mem( multi_mbuf_t *pmb, char *ppmem, u32 szmem, char *pdatanext); extern multi_mbuf_t mmbuf_tx; extern multi_mbuf_t mmbuf_rx; #endif //USE_MULTI_MBUF // EMAC DMA data fifo item: struct __attribute__((__packed__)) emac_dma_data_tx_s { struct emac_dma_data_tx_s *p_next; struct emac_dma_data_tx_s *p_prev; #ifndef USE_MULTI_MBUF char *pbuf __attribute__((aligned(8))); dma_addr_t buf_phys; #endif //!USE_MULTI_MBUF char *pdata; u32 len_data; //struct sk_buff *pskb; //char *pdata; enum emac_dma_data_state_e state; //- текущее состояние элемента }; typedef struct emac_dma_data_tx_s emac_dma_data_tx_t; static inline void emac_dma_data_reset( emac_dma_data_tx_t *pdd) { pdd->len_data = 0; #ifdef USE_MULTI_MBUF pdd->pdata = NULL; #endif // USE_MULTI_MBUF //pdd->pdata = pdd->pbuf; //pdd->pskb = NULL; pdd->state = EDDS_NONE; } //emac_ffi_tx_t //emac_ffi_rx_t // EMAC RX data fifo item: struct __attribute__((__packed__)) emac_dma_data_rx_s { struct emac_dma_data_rx_s *p_next; struct emac_dma_data_rx_s *p_prev; #ifdef USE_MULTI_MBUF char *pbuf; #else // !USE_MULTI_MBUF: char *pbuf __attribute__((aligned(8))); dma_addr_t buf_phys; //struct sk_buff *pskb; //dma_addr_t *p_buf_phys; #endif // !USE_MULTI_MBUF char *pdata; u32 len_data; bool has_error; enum emac_dma_data_state_e state; //- текущее состояние элемента }; typedef struct emac_dma_data_rx_s emac_dma_data_rx_t; static inline void emac_dma_data_rx_reset( emac_dma_data_rx_t *pdd) { #ifdef USE_MULTI_MBUF pdd->pbuf = NULL; #endif //USE_MULTI_MBUF //pdd->pskb = NULL; pdd->pdata = NULL; //pdd->p_buf_phys = NULL; pdd->len_data = 0; pdd->has_error = false; pdd->state = EDDS_NONE; } struct mc_emac_s { #ifdef CONFIG_MULTICORE_ETH_NAPI struct napi_struct napi; #endif void __iomem *eth_regs; //- Указатель на область регистров EMAC void __iomem *dma_rx_regs; //- Указатель на область регистров RX DMA EMAC void __iomem *dma_tx_regs; //- Указатель на область регистров TX DMA EMAC // признаки: bool is_netif_init; //- сетевой интерфейс инициализирован bool is_netif_open; //- сетевой интерфейс открыт bool is_netif_stop_queue; //- выходная очередь сетевого интерфейса остановлена u32 sign_stop_tx_job; //- признак остановки работы по отправке пакетов (0,1,2) u32 sign_stop_rx_job; //- признак остановки работы по приему пакетов (0,1,2) //bool is_in_dma_tx_ih; //- признак того, что мы внутри обработчика emac_dma_tx_ih //bool is_in_frm_tx_ih; //- признак того, что мы внутри обработчика emac_frm_tx_ih bool is_full_ff_rx; //- признак заполненности RX-очереди //int link_up; //- признак наличия соединения int stat_link_down; //- состояние разрыва соединения (0- нет, 1- появился статус от PHY, // 2- все переведено в состояние ожидания соединения) u32 stop_tx; //- признак остановки tx-стороны (0 - нет, 1- запрос на останов, 2- остановлено) u32 stop_rx; //- признак остановки rx-стороны (0 - нет, 1- запрос на останов, 2- остановлено) bool is_param_changing; //- признак текущего изменения параметров (1) // Прерывания: int irq_frm_rx; //- Прерывание по приему кадра или по переполнению входного FIFO int irq_frm_tx; //- Прерывание по завершению попытки передачи пакета int irq_dma_rx; //- Прерывание по завершению приема данных или наличие запроса от Ethernet на передачу при выключенном DMA int irq_dma_tx; //- Прерывание по завершению передачи данных или наличие запроса от Ethernet на передачу при выключенном DMA #ifdef USE_EXT_IRQ_PHY_LINK int irq_phy_link; //- Прерывание по изменению состояния PHY #endif //USE_EXT_IRQ_PHY_LINK // запрошенные к работе прерывания: int req_irq_frm_rx; int req_irq_frm_tx; int req_irq_dma_rx; int req_irq_dma_tx; #ifdef USE_EXT_IRQ_PHY_LINK int req_irq_phy_link; #endif //USE_EXT_IRQ_PHY_LINK // Очереди ожидания: //wait_queue_head_t wq_conn; //- очередь работы с соединением wait_queue_head_t wq_txjob; //- очередь ожидания работы с данными на отправку wait_queue_head_t wq_rxjob; //- очередь ожидания работы с данными на прием // задачи: struct task_struct *p_task_tx_job; struct task_struct *p_task_rx_job; // очереди: fifo_t ffTx; //- FIFO chain (ring list) u32 tx_dma_fifo_size; //- TX DMA fifo size fifo_t ffRx; //- FIFO chain (ring list) u32 rx_dma_fifo_size; //- RX DMA fifo size // указатели на текущие обслуживаемые первые элементы данных из fifo находящиеся в // определенном процессе обработки: emac_dma_data_tx_t *pdtx_mem; //- ук. на первые данные записанные в память emac_dma_data_tx_t *pdtx_dma_to_fifo; //- ук. на данные передаваемые DMA из памяти в TX_FIFO emac_dma_data_tx_t *pdtx_fifo; //- ук. на первые данные загруженные в TX_FIFO emac_dma_data_tx_t *pdtx_fifo_phy; //- ук. на данные передаваемые из FIFO в PHY emac_dma_data_tx_t *pdtx_phy; //- ук. на данные переданные в PHY emac_dma_data_rx_t *pdrx_fifo; //- ук. на первые данные принятые в RX_FIFO emac_dma_data_rx_t *pdrx_dma_to_mem; //- ук. на данные передаваемые DMA из RX_FIFO в память emac_dma_data_rx_t *pdrx_mem; //- ук. на первые данные записанные в память RX char *pbufrx __attribute__((aligned(8))); //- буфер для выгребания ненужных принятых даныых из RX_FIFO struct platform_device *pplatdev; struct net_device *pndev; // Указатель на сетевое устройство unsigned phy; // Адрес внешнего PHY int msg_level; // для ethtool struct mutex mtx_change_work; //- work changing mutex (between from work to stop) // Статистика, печатаемая через /proc /*struct _proc_stat { int rx_lengths [16]; // Гистограмма длина выдаваемых пакетов int tx_lengths [16]; // Гистограмма длина принимаемых пакетов } proc;*/ }; typedef struct mc_emac_s mc_emac_t; extern mc_emac_t *pemac; extern bool mc_phy_write( mc_emac_t *pe, u32 addr, u32 data); extern bool mc_phy_read( mc_emac_t *pe, u32 addr, u32 *pval); extern bool StartDma_MemToTxFifo( mc_emac_t *pe); extern bool Start_TxFrmToPhy( mc_emac_t *pe); extern bool Fin_TxFrm( mc_emac_t *pe); extern bool ProcRxFifo( mc_emac_t *pe, bool permit_dma); extern bool StartDma_RxFifoToMem( mc_emac_t *pe); extern bool emac_init_ff_tx( mc_emac_t *pe); extern bool emac_init_ff_rx( mc_emac_t *pe); extern void emac_reinit_phy( mc_emac_t *pe); extern void reinit_emac( mc_emac_t *pe); extern int emac_set_mac_addr( struct net_device *pnd, void *addr); extern void emac_start_rx( mc_emac_t *pe); extern void emac_stop_rx( mc_emac_t *pe); extern void emac_start_tx( mc_emac_t *pe); extern void emac_stop_tx( mc_emac_t *pe); extern void emac_link_up( mc_emac_t *pe); extern void emac_link_down( mc_emac_t *pe); extern void emac_change_link( mc_emac_t *pe); // DEBUG: // time profiling: extern void print_emac_regs( mc_emac_t *pe); // Profiler: // //#define USE_PROFILER #ifdef USE_PROFILER #define PROFILER_SET_TM(n) \ tmprof_atm[n] = ktime_get_raw_ns(); #define TMPROF_ATM_SIZE 20 extern u64 tmprof_atm[TMPROF_ATM_SIZE]; extern void tmprof_clear(void); #else #define PROFILER_SET_TM(n) #endif //USE_PROFILER #endif // !__emac_h