/* * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #ifndef PCIE_EPF_TEGRA_DMA_H #define PCIE_EPF_TEGRA_DMA_H #define DMA_RD_CHNL_NUM 2 #define DMA_WR_CHNL_NUM 4 #define ENABLE_DMA 1 #define DMA_WR_DATA_CH 0 #define DMA_RD_DATA_CH 0 /* Network link timeout 5 sec */ #define LINK_TIMEOUT 5000 #define TVNET_DEFAULT_MTU 64512 #define TVNET_MIN_MTU 68 #define TVNET_MAX_MTU TVNET_DEFAULT_MTU #define TVNET_NAPI_WEIGHT 64 #define RING_COUNT 256 /* Allocate 100% extra desc to handle the drift between empty & full buffer */ #define DMA_DESC_COUNT (2 * RING_COUNT) /* DMA base offset starts at 0x20000 from ATU_DMA base */ #define DMA_OFFSET 0x20000 /* Common registers */ #define DMA_WRITE_ENGINE_EN_OFF 0xC #define DMA_WRITE_ENGINE_EN_OFF_ENABLE BIT(0) #define DMA_WRITE_ENGINE_EN_OFF_DISABLE 0 #define DMA_WRITE_DOORBELL_OFF 0x10 #define DMA_WRITE_DOORBELL_OFF_WR_STOP BIT(31) #define DMA_READ_ENGINE_EN_OFF 0x2C #define DMA_READ_ENGINE_EN_OFF_ENABLE BIT(0) #define DMA_READ_ENGINE_EN_OFF_DISABLE 0 #define DMA_READ_DOORBELL_OFF 0x30 #define DMA_READ_DOORBELL_OFF_RD_STOP BIT(31) #define DMA_WRITE_INT_STATUS_OFF 0x4C #define DMA_WRITE_INT_MASK_OFF 0x54 #define DMA_WRITE_INT_CLEAR_OFF 0x58 #define DMA_WRITE_DONE_IMWR_LOW_OFF 0x60 #define DMA_WRITE_DONE_IMWR_HIGH_OFF 0x64 #define DMA_WRITE_ABORT_IMWR_LOW_OFF 0x68 #define DMA_WRITE_ABORT_IMWR_HIGH_OFF 0x6C #define DMA_WRITE_IMWR_DATA_OFF_BASE 0x70 #define DMA_WRITE_LINKED_LIST_ERR_EN_OFF 0x90 #define DMA_READ_INT_STATUS_OFF 0xA0 #define DMA_READ_INT_MASK_OFF 0xA8 #define DMA_READ_INT_CLEAR_OFF 0xAC #define DMA_READ_LINKED_LIST_ERR_EN_OFF 0xC4 #define DMA_READ_DONE_IMWR_LOW_OFF 0xCC #define DMA_READ_DONE_IMWR_HIGH_OFF 0xD0 #define DMA_READ_ABORT_IMWR_LOW_OFF 0xD4 #define DMA_READ_ABORT_IMWR_HIGH_OFF 0xD8 #define DMA_READ_IMWR_DATA_OFF_BASE 0xDC /* Channel specific registers */ #define DMA_CH_CONTROL1_OFF_WRCH 0x0 #define DMA_CH_CONTROL1_OFF_WRCH_LLE BIT(9) #define DMA_CH_CONTROL1_OFF_WRCH_CCS BIT(8) #define DMA_CH_CONTROL1_OFF_WRCH_CS_MASK GENMASK(6, 5) #define DMA_CH_CONTROL1_OFF_WRCH_CS_SHIFT 5 #define DMA_CH_CONTROL1_OFF_WRCH_RIE BIT(4) #define DMA_CH_CONTROL1_OFF_WRCH_LIE BIT(3) #define DMA_CH_CONTROL1_OFF_WRCH_LLP BIT(2) #define DMA_CH_CONTROL1_OFF_WRCH_CB BIT(0) #define DMA_TRANSFER_SIZE_OFF_WRCH 0x8 #define DMA_SAR_LOW_OFF_WRCH 0xC #define DMA_SAR_HIGH_OFF_WRCH 0x10 #define DMA_DAR_LOW_OFF_WRCH 0x14 #define DMA_DAR_HIGH_OFF_WRCH 0x18 #define DMA_LLP_LOW_OFF_WRCH 0x1C #define DMA_LLP_HIGH_OFF_WRCH 0x20 #define DMA_CH_CONTROL1_OFF_RDCH 0x100 #define DMA_CH_CONTROL1_OFF_RDCH_LLE BIT(9) #define DMA_CH_CONTROL1_OFF_RDCH_CCS BIT(8) #define DMA_CH_CONTROL1_OFF_RDCH_CS_MASK GENMASK(6, 5) #define DMA_CH_CONTROL1_OFF_RDCH_CS_SHIFT 5 #define DMA_CH_CONTROL1_OFF_RDCH_RIE BIT(4) #define DMA_CH_CONTROL1_OFF_RDCH_LIE BIT(3) #define DMA_CH_CONTROL1_OFF_RDCH_LLP BIT(2) #define DMA_CH_CONTROL1_OFF_RDCH_CB BIT(0) #define DMA_TRANSFER_SIZE_OFF_RDCH 0x108 #define DMA_SAR_LOW_OFF_RDCH 0x10c #define DMA_SAR_HIGH_OFF_RDCH 0x110 #define DMA_DAR_LOW_OFF_RDCH 0x114 #define DMA_DAR_HIGH_OFF_RDCH 0x118 #define DMA_LLP_LOW_OFF_RDCH 0x11c #define DMA_LLP_HIGH_OFF_RDCH 0x120 static inline void dma_common_wr(void __iomem *p, u32 val, u32 offset) { writel(val, p + offset); } static inline void dma_common_wr16(void __iomem *p, u16 val, u32 offset) { writew(val, p + offset); } static inline void dma_common_wr8(void __iomem *p, u16 val, u32 offset) { writeb(val, p + offset); } static inline u32 dma_common_rd(void __iomem *p, u32 offset) { return readl(p + offset); } static inline void dma_channel_wr(void __iomem *p, u8 channel, u32 val, u32 offset) { writel(val, (0x200 * (channel + 1)) + p + offset); } static inline u32 dma_channel_rd(void __iomem *p, u8 channel, u32 offset) { return readl((0x200 * (channel + 1)) + p + offset); } struct tvnet_dma_ctrl { u32 cb:1; u32 tcb:1; u32 llp:1; u32 lie:1; u32 rie:1; }; struct tvnet_dma_desc { volatile union { struct tvnet_dma_ctrl ctrl_e; u32 ctrl_d; } ctrl_reg; u32 size; u32 sar_low; u32 sar_high; u32 dar_low; u32 dar_high; }; enum irq_type { /* No IRQ available in this slot */ IRQ_NOT_AVAILABLE = 0, /* Use irq_{addr,val} fields */ IRQ_SIMPLE = 1, /* Perform a dummy DMA reading */ IRQ_DUMMY_DMA = 2, }; struct irq_md { u32 irq_type; /* Simple method: Write to this */ /* Dummy DMA method: Read from this */ u64 irq_addr; /* Simple method: Write this value */ /* Dummy DMA method: Don’t use this value */ u32 irq_val; u32 reserved[4]; }; enum ring_buf { H2EP_CTRL, EP2H_CTRL, EP2H_EMPTY_BUF, EP2H_FULL_BUF, H2EP_FULL_BUF, H2EP_EMPTY_BUF, }; struct ring_buf_md { u32 h2ep_offset; u32 h2ep_size; u32 ep2h_offset; u32 ep2h_size; }; struct bar_md { /* IRQ generation for control packets */ struct irq_md irq_ctrl; /* IRQ generation for data packets */ struct irq_md irq_data; /* Ring buffers counter offset */ u32 ep_own_cnt_offset; u32 host_own_cnt_offset; /* Ring buffers location offset */ struct ring_buf_md ctrl_md; struct ring_buf_md ep2h_md; struct ring_buf_md h2ep_md; /* RAM region for use by host when programming EP DMA controller */ u32 host_dma_offset; u32 host_dma_size; /* Endpoint will map all RX packet buffers into this region */ u64 bar0_base_phy; u32 ep_rx_pkt_offset; u32 ep_rx_pkt_size; }; enum ctrl_msg_type { CTRL_MSG_RESERVED, CTRL_MSG_LINK_UP, CTRL_MSG_LINK_DOWN, CTRL_MSG_LINK_DOWN_ACK, }; struct ctrl_msg { u32 msg_id; /* enum ctrl_msg_type */ union { u32 reserved[7]; } u; }; enum data_msg_type { DATA_MSG_RESERVED, DATA_MSG_EMPTY_BUF, DATA_MSG_FULL_BUF, }; struct data_msg { u32 msg_id; /* enum data_msg_type */ union { struct { u32 buffer_len; u64 pcie_address; } empty_buffer; struct { u32 packet_size; u64 pcie_address; } full_buffer; u32 reserved[7]; } u; }; struct tvnet_counter { u32 *rd; u32 *wr; }; struct ep_own_cnt { u32 h2ep_ctrl_rd_cnt; u32 ep2h_ctrl_wr_cnt; u32 ep2h_empty_rd_cnt; u32 ep2h_full_wr_cnt; u32 h2ep_full_rd_cnt; u32 h2ep_empty_wr_cnt; }; struct ep_ring_buf { struct ep_own_cnt *ep_cnt; /* Endpoint written message buffers */ struct ctrl_msg *ep2h_ctrl_msgs; struct data_msg *ep2h_full_msgs; struct data_msg *h2ep_empty_msgs; }; struct host_own_cnt { u32 h2ep_ctrl_wr_cnt; u32 ep2h_ctrl_rd_cnt; u32 ep2h_empty_wr_cnt; u32 ep2h_full_rd_cnt; u32 h2ep_full_wr_cnt; u32 h2ep_empty_rd_cnt; }; struct host_ring_buf { struct host_own_cnt *host_cnt; /* Host written message buffers */ struct ctrl_msg *h2ep_ctrl_msgs; struct data_msg *ep2h_empty_msgs; struct data_msg *h2ep_full_msgs; }; struct ep2h_empty_list { int len; dma_addr_t iova; struct sk_buff *skb; struct list_head list; }; struct h2ep_empty_list { int size; #if ENABLE_DMA struct sk_buff *skb; #else struct page *page; void *virt; #endif dma_addr_t iova; struct list_head list; }; enum dir_link_state { DIR_LINK_STATE_DOWN, DIR_LINK_STATE_UP, DIR_LINK_STATE_SENT_DOWN, }; enum os_link_state { OS_LINK_STATE_UP, OS_LINK_STATE_DOWN, }; #if ENABLE_DMA struct dma_desc_cnt { u32 rd_cnt; u32 wr_cnt; }; #endif static inline bool tvnet_ivc_empty(struct tvnet_counter *counter) { u32 rd, wr; wr = READ_ONCE(*counter->wr); rd = READ_ONCE(*counter->rd); if (wr - rd > RING_COUNT) return true; return wr == rd; } static inline bool tvnet_ivc_full(struct tvnet_counter *counter) { u32 rd, wr; wr = READ_ONCE(*counter->wr); rd = READ_ONCE(*counter->rd); return wr - rd >= RING_COUNT; } static inline u32 tvnet_ivc_rd_available(struct tvnet_counter *counter) { u32 rd, wr; wr = READ_ONCE(*counter->wr); rd = READ_ONCE(*counter->rd); return wr - rd; } static inline u32 tvnet_ivc_wr_available(struct tvnet_counter *counter) { u32 rd, wr; wr = READ_ONCE(*counter->wr); rd = READ_ONCE(*counter->rd); return (RING_COUNT - (wr - rd)); } static inline void tvnet_ivc_advance_wr(struct tvnet_counter *counter) { WRITE_ONCE(*counter->wr, READ_ONCE(*counter->wr) + 1); /* BAR0 mmio address is wc mem, add mb to make sure cnts are updated */ smp_mb(); } static inline void tvnet_ivc_advance_rd(struct tvnet_counter *counter) { WRITE_ONCE(*counter->rd, READ_ONCE(*counter->rd) + 1); /* BAR0 mmio address is wc mem, add mb to make sure cnts are updated */ smp_mb(); } static inline void tvnet_ivc_set_wr(struct tvnet_counter *counter, u32 val) { WRITE_ONCE(*counter->wr, val); /* BAR0 mmio address is wc mem, add mb to make sure cnts are updated */ smp_mb(); } static inline void tvnet_ivc_set_rd(struct tvnet_counter *counter, u32 val) { WRITE_ONCE(*counter->rd, val); /* BAR0 mmio address is wc mem, add mb to make sure cnts are updated */ smp_mb(); } static inline u32 tvnet_ivc_get_wr_cnt(struct tvnet_counter *counter) { return READ_ONCE(*counter->wr); } static inline u32 tvnet_ivc_get_rd_cnt(struct tvnet_counter *counter) { return READ_ONCE(*counter->rd); } #endif