343 lines
9 KiB
C
Executable file
343 lines
9 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com/
|
|
*
|
|
* EXYNOS DIT(Direct IP Translator) Driver support
|
|
*
|
|
*/
|
|
|
|
#ifndef __DIT_COMMON_H__
|
|
#define __DIT_COMMON_H__
|
|
|
|
#ifndef DIT_DEBUG
|
|
#define DIT_DEBUG
|
|
#endif
|
|
|
|
#ifdef DIT_DEBUG
|
|
#define DIT_DEBUG_LOW
|
|
#endif
|
|
|
|
#include "dit.h"
|
|
#include "cpif_page.h"
|
|
|
|
#define DIT_VERSION(x, y, z) \
|
|
((((x) & 0xFF) << 24) | (((y) & 0xFF) << 16) | (((z) & 0xFF) << 8))
|
|
|
|
#if defined(CONFIG_EXYNOS_DIT_VERSION) && (DIT_VERSION(2, 2, 0) == CONFIG_EXYNOS_DIT_VERSION)
|
|
#include "dit_2_2_0.h"
|
|
#else
|
|
#include "dit_2_1_0.h"
|
|
#endif
|
|
|
|
#define DIT_REG_SW_COMMAND 0x0000
|
|
|
|
/* total: DIT_REG_CLAT_ADDR_MAX, interval: DIT_REG_CLAT_TX_FILTER_INTERVAL */
|
|
#define DIT_REG_CLAT_TX_FILTER 0x2000
|
|
/* total: DIT_REG_CLAT_ADDR_MAX, interval: DIT_REG_CLAT_TX_PLAT_PREFIX_INTERVAL */
|
|
#define DIT_REG_CLAT_TX_PLAT_PREFIX_0 0x2020
|
|
#define DIT_REG_CLAT_TX_PLAT_PREFIX_1 0x2024
|
|
#define DIT_REG_CLAT_TX_PLAT_PREFIX_2 0x2028
|
|
/* total: DIT_REG_CLAT_ADDR_MAX, interval: DIT_REG_CLAT_TX_CLAT_SRC_INTERVAL */
|
|
#define DIT_REG_CLAT_TX_CLAT_SRC_0 0x2080
|
|
#define DIT_REG_CLAT_TX_CLAT_SRC_1 0x2084
|
|
#define DIT_REG_CLAT_TX_CLAT_SRC_2 0x2088
|
|
#define DIT_REG_CLAT_TX_CLAT_SRC_3 0x208C
|
|
|
|
/* total: DIT_REG_NAT_LOCAL_ADDR_MAX, interval: DIT_REG_NAT_LOCAL_INTERVAL */
|
|
#define DIT_REG_NAT_LOCAL_ADDR 0x4100
|
|
|
|
#define DIT_REG_NAT_ZERO_CHK_OFF 0x4144
|
|
#define DIT_REG_NAT_ETHERNET_EN 0x414C
|
|
|
|
/* total: DIT_REG_NAT_LOCAL_ADDR_MAX, interval: DIT_REG_ETHERNET_MAC_INTERVAL */
|
|
#define DIT_REG_NAT_ETHERNET_DST_MAC_ADDR_0 0x6000 /* 32 bit */
|
|
#define DIT_REG_NAT_ETHERNET_DST_MAC_ADDR_1 0x6004 /* 16 bit */
|
|
#define DIT_REG_NAT_ETHERNET_SRC_MAC_ADDR_0 0x6008 /* 32 bit */
|
|
#define DIT_REG_NAT_ETHERNET_SRC_MAC_ADDR_1 0x600C /* 16 bit */
|
|
#define DIT_REG_NAT_ETHERNET_TYPE 0x6010 /* 16 bit */
|
|
|
|
#define DIT_REG_NAT_TX_PORT_INIT_START 0x6210
|
|
#define DIT_REG_NAT_TX_PORT_INIT_DONE 0x6214
|
|
#define DIT_REG_NAT_RX_PORT_INIT_START 0x6228
|
|
#define DIT_REG_NAT_RX_PORT_INIT_DONE 0x622C
|
|
|
|
/* total: DIT_REG_NAT_LOCAL_PORT_MAX, interval: DIT_REG_NAT_LOCAL_INTERVAL */
|
|
#define DIT_REG_NAT_RX_PORT_TABLE_SLOT 0xC000
|
|
|
|
/* total numbers and intervals */
|
|
#define DIT_REG_NAT_LOCAL_ADDR_MAX (16)
|
|
#define DIT_REG_NAT_LOCAL_PORT_MAX (2048)
|
|
#define DIT_REG_NAT_LOCAL_INTERVAL (4)
|
|
#define DIT_REG_ETHERNET_MAC_INTERVAL (0x20)
|
|
#define DIT_REG_CLAT_ADDR_MAX (8)
|
|
#define DIT_REG_CLAT_TX_FILTER_INTERVAL (4)
|
|
#define DIT_REG_CLAT_TX_PLAT_PREFIX_INTERVAL (12)
|
|
#define DIT_REG_CLAT_TX_CLAT_SRC_INTERVAL (16)
|
|
|
|
/* macro for DIT register operation */
|
|
#define WRITE_REG_PADDR_LO(dc, paddr, offset) \
|
|
writel(PADDR_LO(paddr), dc->register_base + offset)
|
|
#define WRITE_REG_PADDR_HI(dc, paddr, offset) \
|
|
writel(PADDR_HI(paddr), dc->register_base + offset)
|
|
#define WRITE_REG_VALUE(dc, value, offset) \
|
|
writel(value, dc->register_base + offset)
|
|
#define READ_REG_VALUE(dc, offset) \
|
|
readl(dc->register_base + offset)
|
|
#define WRITE_SHR_VALUE(dc, value) \
|
|
({ \
|
|
if (!IS_ERR_OR_NULL(dc->sharability_base)) \
|
|
writel(value, dc->sharability_base + dc->sharability_offset); \
|
|
})
|
|
#define BACKUP_REG_VALUE(dc, dst, offset, size) \
|
|
memcpy_fromio(dst, dc->register_base + offset, size)
|
|
#define RESTORE_REG_VALUE(dc, src, offset, size) \
|
|
memcpy_toio(dc->register_base + offset, src, size)
|
|
|
|
/* macro for DIT function pointer */
|
|
#define DIT_INDIRECT_CALL(dc, f, ...) \
|
|
({ \
|
|
dc->f ? dc->f(__VA_ARGS__) : -EOPNOTSUPP; \
|
|
})
|
|
|
|
#define DIT_RX_BURST_16BEAT (0)
|
|
|
|
enum dit_desc_ring {
|
|
DIT_DST_DESC_RING_0,
|
|
DIT_DST_DESC_RING_1,
|
|
DIT_DST_DESC_RING_2,
|
|
DIT_DST_DESC_RING_MAX,
|
|
DIT_SRC_DESC_RING = DIT_DST_DESC_RING_MAX,
|
|
DIT_DESC_RING_MAX
|
|
};
|
|
|
|
enum dit_desc_control_bits {
|
|
DIT_DESC_C_RESERVED, /* Reserved */
|
|
DIT_DESC_C_END, /* end packet of LRO */
|
|
DIT_DESC_C_START, /* first packet of LRO */
|
|
DIT_DESC_C_RINGEND, /* End of descriptor */
|
|
DIT_DESC_C_INT, /* Interrupt enabled */
|
|
DIT_DESC_C_CSUM, /* csum enabled */
|
|
DIT_DESC_C_TAIL, /* last buffer */
|
|
DIT_DESC_C_HEAD /* first buffer */
|
|
};
|
|
|
|
#define DIT_SRC_KICK_CONTROL_MASK \
|
|
(BIT(DIT_DESC_C_HEAD) | BIT(DIT_DESC_C_TAIL) | \
|
|
BIT(DIT_DESC_C_INT) | BIT(DIT_DESC_C_RINGEND))
|
|
|
|
enum dit_desc_status_bits {
|
|
DIT_DESC_S_DONE, /* DMA done */
|
|
DIT_DESC_S_RESERVED, /* Reserved */
|
|
DIT_DESC_S_TCPCF, /* Failed TCP csum */
|
|
DIT_DESC_S_IPCSF, /* Failed IP csum */
|
|
DIT_DESC_S_IGNR, /* Ignore csum */
|
|
DIT_DESC_S_TCPC, /* TCP/UDP csum done: should be 0 if IGNR */
|
|
DIT_DESC_S_IPCS, /* IP header csum done: should be 0 if IGNR */
|
|
DIT_DESC_S_PFD /* passed packet filter */
|
|
};
|
|
|
|
#define DIT_CHECKSUM_FAILED_STATUS_MASK \
|
|
(BIT(DIT_DESC_S_TCPCF) | BIT(DIT_DESC_S_IPCSF) | BIT(DIT_DESC_S_IGNR))
|
|
|
|
enum dit_sw_command_bits {
|
|
DMA_INIT_COMMAND_BIT,
|
|
TX_COMMAND_BIT,
|
|
RX_COMMAND_BIT,
|
|
};
|
|
|
|
enum dit_nat_ethernet_en_bits {
|
|
TX_ETHERNET_EN_BIT,
|
|
RX_ETHERNET_EN_BIT,
|
|
};
|
|
|
|
#define DIT_ALL_INT_PENDING_MASK \
|
|
(DIT_TX_INT_PENDING_MASK | DIT_RX_INT_PENDING_MASK)
|
|
|
|
/* DIT_STATUS
|
|
* zero means idle
|
|
*/
|
|
enum dit_status_mask {
|
|
TX_STATUS_MASK = 0x0F,
|
|
RX_STATUS_MASK = 0xF0,
|
|
};
|
|
|
|
enum dit_packet_info_bits {
|
|
DIT_PACKET_INFO_UDP_BIT = 6,
|
|
DIT_PACKET_INFO_TCP_BIT,
|
|
DIT_PACKET_INFO_IPV6_BIT = 10,
|
|
DIT_PACKET_INFO_IPV4_BIT,
|
|
};
|
|
|
|
struct dit_dst_desc {
|
|
u64 dst_addr:36,
|
|
packet_info:12,
|
|
/* the below 16 bits are "private info" on the document */
|
|
ch_id:8,
|
|
pre_csum:1,
|
|
udp_csum_zero:1,
|
|
_reserved_2:6;
|
|
u64 length:16,
|
|
org_port:16,
|
|
trans_port:16,
|
|
control:8,
|
|
status:8;
|
|
} __packed;
|
|
|
|
struct dit_desc_info {
|
|
unsigned int src_wp;
|
|
unsigned int src_rp;
|
|
unsigned int dst_wp[DIT_DST_DESC_RING_MAX];
|
|
unsigned int dst_rp[DIT_DST_DESC_RING_MAX];
|
|
|
|
unsigned int src_desc_ring_len;
|
|
struct dit_src_desc *src_desc_ring;
|
|
struct sk_buff **src_skb_buf;
|
|
u32 buf_size;
|
|
|
|
phys_addr_t pktproc_pbase;
|
|
u32 pktproc_queue_num;
|
|
u32 pktproc_desc_len;
|
|
u32 *pktproc_fore_ptr;
|
|
|
|
unsigned int dst_desc_ring_len;
|
|
struct dit_dst_desc *dst_desc_ring[DIT_DST_DESC_RING_MAX];
|
|
struct sk_buff **dst_skb_buf[DIT_DST_DESC_RING_MAX];
|
|
bool dst_skb_buf_filled[DIT_DST_DESC_RING_MAX];
|
|
|
|
/* use_dma_map */
|
|
dma_addr_t src_desc_ring_daddr;
|
|
dma_addr_t dst_desc_ring_daddr[DIT_DST_DESC_RING_MAX];
|
|
dma_addr_t *dst_skb_buf_daddr[DIT_DST_DESC_RING_MAX];
|
|
|
|
/* page pool */
|
|
struct cpif_page_pool *dst_page_pool[DIT_DST_DESC_RING_MAX];
|
|
};
|
|
|
|
struct dit_ctrl_t {
|
|
spinlock_t rx_buf_lock;
|
|
struct device *dev;
|
|
struct link_device *ld;
|
|
struct net_device *netdev;
|
|
struct napi_struct napi;
|
|
int *irq_pending_bit;
|
|
char const **irq_name;
|
|
int *irq_buf;
|
|
int irq_len;
|
|
int irq_affinity;
|
|
int irq_num_tx;
|
|
int irq_affinity_tx;
|
|
int idle_ip_index;
|
|
|
|
void __iomem *register_base;
|
|
void __iomem *sharability_base;
|
|
u32 sharability_offset;
|
|
u32 sharability_value;
|
|
bool use_dma_map;
|
|
|
|
u32 hw_version;
|
|
u32 reg_version;
|
|
u32 hw_capabilities;
|
|
bool use_dir[DIT_DIR_MAX];
|
|
bool stop_enqueue[DIT_DIR_MAX];
|
|
bool use_clat;
|
|
bool hal_support;
|
|
bool hal_enqueue_rx;
|
|
u32 rx_extra_desc_ring_len;
|
|
|
|
struct dit_desc_info desc_info[DIT_DIR_MAX];
|
|
|
|
/* for kicked flag, reg_value_q and init_done */
|
|
spinlock_t src_lock;
|
|
bool kicked[DIT_DIR_MAX];
|
|
bool kick_reserved[DIT_DIR_MAX];
|
|
struct list_head reg_value_q;
|
|
bool init_done;
|
|
bool init_reserved;
|
|
|
|
atomic_t init_running;
|
|
atomic_t stop_napi_poll;
|
|
|
|
bool use_page_recycling_rx;
|
|
u32 page_recycling_skb_padding;
|
|
|
|
#if defined(DIT_DEBUG_LOW)
|
|
int pktgen_ch;
|
|
int force_bypass;
|
|
#endif
|
|
|
|
/* every functions should return int for DIT_INDIRECT_CALL */
|
|
int (*get_reg_version)(u32 *version);
|
|
int (*set_reg_upstream)(struct net_device *netdev);
|
|
int (*set_desc_filter_bypass)(enum dit_direction dir, struct dit_src_desc *src_desc,
|
|
u8 *src, bool *is_upstream_pkt);
|
|
int (*set_src_desc_tail)(enum dit_direction dir, struct dit_desc_info *desc_info,
|
|
unsigned int tail);
|
|
int (*do_init_hw)(void);
|
|
int (*do_init_desc)(enum dit_direction dir);
|
|
};
|
|
|
|
struct dit_snapshot_t {
|
|
char *name;
|
|
int head;
|
|
int tail;
|
|
|
|
u64 packets;
|
|
/* cumulative amount */
|
|
u64 total_packets;
|
|
u64 clat_packets;
|
|
|
|
u32 max_usage;
|
|
u32 alloc_skbs;
|
|
u32 dma_maps;
|
|
};
|
|
|
|
struct dit_reg_value_item {
|
|
struct list_head list;
|
|
u32 value;
|
|
u32 offset;
|
|
};
|
|
|
|
struct dit_iface {
|
|
u8 upstream_ch;
|
|
};
|
|
|
|
enum dit_dump_bits {
|
|
DIT_DUMP_SNAPSHOT_BIT,
|
|
DIT_DUMP_DESC_BIT,
|
|
DIT_DUMP_PORT_TABLE_BIT,
|
|
DIT_DUMP_MAX,
|
|
};
|
|
|
|
#define DIT_DUMP_ALL \
|
|
(BIT(DIT_DUMP_SNAPSHOT_BIT) | BIT(DIT_DUMP_DESC_BIT) | \
|
|
BIT(DIT_DUMP_PORT_TABLE_BIT))
|
|
|
|
enum dit_idle_ip {
|
|
DIT_IDLE_IP_ACTIVE = 0,
|
|
DIT_IDLE_IP_IDLE,
|
|
};
|
|
|
|
/*
|
|
* if there is 1 src desc and it is at the ring_end,
|
|
* DIT will reads 3 descs from the ring_end.
|
|
* for the safety, add additional 2 descs.
|
|
*/
|
|
#define DIT_SRC_DESC_RING_LEN_PADDING (2)
|
|
|
|
/* prevent zero size alloc */
|
|
#define DIT_DST_DESC_RING_LEN_PADDING (1)
|
|
|
|
bool dit_is_kicked_any(void);
|
|
int dit_check_dst_ready(enum dit_direction dir, enum dit_desc_ring ring_num);
|
|
int dit_enqueue_reg_value_with_ext_lock(u32 value, u32 offset);
|
|
int dit_enqueue_reg_value(u32 value, u32 offset);
|
|
int dit_read_rx_dst_poll(struct napi_struct *napi, int budget);
|
|
int dit_manage_rx_dst_data_buffers(bool fill);
|
|
bool dit_is_busy(enum dit_direction dir);
|
|
int dit_stop_napi_poll(void);
|
|
|
|
int dit_ver_create(struct dit_ctrl_t *dc_ptr);
|
|
|
|
#endif /* __DIT_COMMON_H__ */
|
|
|