/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2020-2023, NVIDIA CORPORATION.  All rights reserved.
 */

#ifndef PCIE_EPF_TEGRA_DMA_H
#define PCIE_EPF_TEGRA_DMA_H

#ifndef PCI_DEVICE_ID_NVIDIA_JETSON_AGX_NETWORK
#define PCI_DEVICE_ID_NVIDIA_JETSON_AGX_NETWORK     0x2296
#endif

#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
