/*-
 * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates
 * All rights reserved.
 *
 * Developed by Semihalf.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef __AL_ETH_H__
#define	__AL_ETH_H__

#include "al_init_eth_lm.h"
#include "al_hal_eth.h"
#include "al_hal_udma_iofic.h"
#include "al_hal_udma_debug.h"
#include "al_serdes.h"

enum board_t {
	ALPINE_INTEGRATED = 0,
	ALPINE_NIC = 1,
	ALPINE_FPGA_NIC = 2,
};

#define	AL_ETH_MAX_HW_QUEUES	4
#define	AL_ETH_NUM_QUEUES	4
#define	AL_ETH_MAX_MSIX_VEC	(1 + 2 * AL_ETH_MAX_HW_QUEUES)

#define AL_ETH_DEFAULT_TX_SW_DESCS	(512)
#define AL_ETH_DEFAULT_TX_HW_DESCS	(512)
#define AL_ETH_DEFAULT_RX_DESCS		(512)

#if ((AL_ETH_DEFAULT_TX_SW_DESCS / 4) < (AL_ETH_PKT_MAX_BUFS + 2))
#define	AL_ETH_TX_WAKEUP_THRESH		(AL_ETH_DEFAULT_TX_SW_DESCS / 4)
#else
#define	AL_ETH_TX_WAKEUP_THRESH		(AL_ETH_PKT_MAX_BUFS + 2)
#endif

#define	NET_IP_ALIGN				2
#define	AL_ETH_DEFAULT_SMALL_PACKET_LEN		(128 - NET_IP_ALIGN)
#define	AL_ETH_HEADER_COPY_SIZE			(128 - NET_IP_ALIGN)

#define	AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE	9216
/*
 * Minimum the buffer size to 600 to avoid situation the mtu will be changed
 * from too little buffer to very big one and then the number of buffer per
 * packet could reach the maximum AL_ETH_PKT_MAX_BUFS
 */
#define	AL_ETH_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE	600
#define	AL_ETH_DEFAULT_FORCE_1000_BASEX FALSE

#define	AL_ETH_DEFAULT_LINK_POLL_INTERVAL	100
#define	AL_ETH_FIRST_LINK_POLL_INTERVAL		1

#define	AL_ETH_NAME_MAX_LEN	20
#define	AL_ETH_IRQNAME_SIZE	40

#define	AL_ETH_DEFAULT_MDIO_FREQ_KHZ	2500
#define	AL_ETH_MDIO_FREQ_1000_KHZ	1000

struct al_eth_irq {
	driver_filter_t *handler;
	void		*data;
	unsigned int	vector;
	uint8_t		requested;
	char		name[AL_ETH_IRQNAME_SIZE];
	struct resource *res;
	void		*cookie;
};

struct al_eth_tx_buffer {
	struct mbuf *m;
	struct al_eth_pkt hal_pkt;
	bus_dmamap_t	dma_map;
	unsigned int	tx_descs;
};

struct al_eth_rx_buffer {
	struct mbuf	*m;
	unsigned int	data_size;
	bus_dmamap_t	dma_map;
	struct al_buf	al_buf;
};

struct al_eth_ring {
	device_t dev;
	struct al_eth_adapter *adapter;
	/* Used to get rx packets from hal */
	struct al_eth_pkt hal_pkt;
	/* Udma queue handler */
	struct al_udma_q *dma_q;
	uint32_t ring_id;
	uint16_t next_to_use;
	uint16_t next_to_clean;
	/* The offset of the interrupt unmask register */
	uint32_t *unmask_reg_offset;
	/* 
	 * The value to write to the above register to
	 * unmask the interrupt of this ring
	 */
	uint32_t unmask_val;
	struct al_eth_meta_data hal_meta;
	/* Contex of tx packet */
	struct al_eth_tx_buffer *tx_buffer_info;
	/* Contex of rx packet */
	struct al_eth_rx_buffer *rx_buffer_info;
	/* Number of tx/rx_buffer_info's entries */
	int sw_count;
	/* Number of hw descriptors */
	int hw_count;
	/* Size (in bytes) of hw descriptors */
	size_t descs_size;
	/* Size (in bytes) of hw completion descriptors, used for rx */
	size_t cdescs_size;
	struct ifnet *netdev;
	struct al_udma_q_params	q_params;
	struct buf_ring *br;
	struct mtx br_mtx;
	struct task enqueue_task;
	struct taskqueue *enqueue_tq;
	volatile uint32_t enqueue_is_running;
	struct task cmpl_task;
	struct taskqueue *cmpl_tq;
	volatile uint32_t cmpl_is_running;
	uint32_t lro_enabled;
	struct lro_ctrl lro;
	bus_dma_tag_t dma_buf_tag;
	volatile uint32_t stall;
};

#define	AL_ETH_TX_RING_IDX_NEXT(tx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_TX_SW_DESCS - 1))

#define	AL_ETH_RX_RING_IDX_NEXT(rx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_RX_DESCS - 1))
#define	AL_ETH_RX_RING_IDX_ADD(rx_ring, idx, n) (((idx) + (n)) & (AL_ETH_DEFAULT_RX_DESCS - 1))

/* flow control configuration */
#define	AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH	0x160
#define	AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW		0x90
#define	AL_ETH_FLOW_CTRL_QUANTA			0xffff
#define	AL_ETH_FLOW_CTRL_QUANTA_TH		0x8000

#define	AL_ETH_FLOW_CTRL_AUTONEG	1 
#define	AL_ETH_FLOW_CTRL_RX_PAUSE	2
#define	AL_ETH_FLOW_CTRL_TX_PAUSE	4

/* link configuration for 1G port */
struct al_eth_link_config {
	int old_link;
	/* Describes what we actually have. */
	int	active_duplex;
	int	active_speed;

	/* current flow control status */
	uint8_t flow_ctrl_active;
	/* supported configuration (can be changed from ethtool) */
	uint8_t flow_ctrl_supported;

	/* the following are not relevant to RGMII */
	bool	force_1000_base_x;
	bool	autoneg;
};

/* SFP detection event */
enum al_eth_sfp_detect_evt {
	/* No change (no connect, disconnect, or new SFP module */
	AL_ETH_SFP_DETECT_EVT_NO_CHANGE,
	/* SFP module connected */
	AL_ETH_SFP_DETECT_EVT_CONNECTED,
	/* SFP module disconnected */
	AL_ETH_SFP_DETECT_EVT_DISCONNECTED,
	/* SFP module replaced */
	AL_ETH_SFP_DETECT_EVT_CHANGED,
};

/* SFP detection status */
struct al_eth_sfp_detect_stat {
	/* Status is valid (i.e. rest of fields are valid) */
	bool			valid;
	bool			connected;
	uint8_t			sfp_10g;
	uint8_t			sfp_1g;
	uint8_t			sfp_cable_tech;
	bool			lt_en;
	bool			an_en;
	enum al_eth_mac_mode	mac_mode;
};

struct al_eth_retimer_params {
	bool				exist;
	uint8_t				bus_id;
	uint8_t				i2c_addr;
	enum al_eth_retimer_channel	channel;
};

struct msix_entry {
	int entry;
	int vector;
};

/* board specific private data structure */
struct al_eth_adapter {
	enum board_t	board_type;
	device_t	miibus;
	struct mii_data *mii;
	uint16_t dev_id;
	uint8_t rev_id;

	device_t dev;
	struct ifnet *netdev;
	struct ifmedia media;
	struct resource	*udma_res;
	struct resource	*mac_res;
	struct resource	*ec_res;
	int if_flags;
	struct callout wd_callout;
	struct mtx     wd_mtx;
	struct callout stats_callout;
	struct mtx     stats_mtx;

	/* this is for intx mode */
	void *irq_cookie;
	struct resource *irq_res;

	/* 
	 * Some features need tri-state capability,
	 * thus the additional *_CAPABLE flags.
	 */
	uint32_t flags;
#define	AL_ETH_FLAG_MSIX_CAPABLE		(uint32_t)(1 << 1)
#define	AL_ETH_FLAG_MSIX_ENABLED		(uint32_t)(1 << 2)
#define	AL_ETH_FLAG_IN_NETPOLL			(uint32_t)(1 << 3)
#define	AL_ETH_FLAG_MQ_CAPABLE			(uint32_t)(1 << 4)
#define	AL_ETH_FLAG_SRIOV_CAPABLE		(uint32_t)(1 << 5)
#define	AL_ETH_FLAG_SRIOV_ENABLED		(uint32_t)(1 << 6)
#define	AL_ETH_FLAG_RESET_REQUESTED		(uint32_t)(1 << 7)

	struct al_hal_eth_adapter hal_adapter;

	/*
	 * Rx packets that shorter that this len will be copied to the mbuf 
	 */
	unsigned int small_copy_len;

	/* Maximum size for rx buffer */
	unsigned int max_rx_buff_alloc_size;
	uint32_t rx_mbuf_sz;

	/* Tx fast path data */
	int num_tx_queues;

	/* Rx fast path data */
	int num_rx_queues;

	/* TX */
	struct al_eth_ring tx_ring[AL_ETH_NUM_QUEUES];

	/* RX */
	struct al_eth_ring rx_ring[AL_ETH_NUM_QUEUES];

	enum al_iofic_mode int_mode;

#define	AL_ETH_MGMT_IRQ_IDX		0
#define	AL_ETH_RXQ_IRQ_IDX(adapter, q)	(1 + (q))
#define	AL_ETH_TXQ_IRQ_IDX(adapter, q)	(1 + (adapter)->num_rx_queues + (q))
	struct al_eth_irq irq_tbl[AL_ETH_MAX_MSIX_VEC];
	struct msix_entry *msix_entries;
	int	msix_vecs;
	int	irq_vecs;

	unsigned int tx_usecs, rx_usecs; /* interrupt coalescing */

	unsigned int tx_ring_count;
	unsigned int tx_descs_count;
	unsigned int rx_ring_count;
	unsigned int rx_descs_count;

	/* RSS */
	uint32_t toeplitz_hash_key[AL_ETH_RX_HASH_KEY_NUM];
#define	AL_ETH_RX_RSS_TABLE_SIZE	AL_ETH_RX_THASH_TABLE_SIZE
	uint8_t	 rss_ind_tbl[AL_ETH_RX_RSS_TABLE_SIZE];

	uint32_t msg_enable;
	struct al_eth_mac_stats mac_stats;

	enum al_eth_mac_mode	mac_mode;
	bool			mac_mode_set; /* Relevant only when 'auto_speed' is set */
	uint8_t mac_addr[ETHER_ADDR_LEN];
	/* mdio and phy*/
	bool			phy_exist;
	struct mii_bus		*mdio_bus;
	struct phy_device	*phydev;
	uint8_t			phy_addr;
	struct al_eth_link_config	link_config;

	/* HAL layer data */
	int			id_number;
	char			name[AL_ETH_NAME_MAX_LEN];
	void			*internal_pcie_base; /* use for ALPINE_NIC devices */
	void			*udma_base;
	void			*ec_base;
	void			*mac_base;

	struct al_eth_flow_control_params flow_ctrl_params;

	struct al_eth_adapter_params eth_hal_params;

	struct task			link_status_task;
	uint32_t			link_poll_interval; /* task interval in mSec */

	bool				serdes_init;
	struct al_serdes_grp_obj	serdes_obj;
	uint8_t				serdes_grp;
	uint8_t				serdes_lane;

	bool				an_en;	/* run kr auto-negotiation */
	bool				lt_en;	/* run kr link-training */

	bool				sfp_detection_needed; /* true if need to run sfp detection */
	bool				auto_speed; /* true if allowed to change SerDes speed configuration */
	uint8_t				i2c_adapter_id; /* identifier for the i2c adapter to use to access SFP+ module */
	enum al_eth_ref_clk_freq	ref_clk_freq; /* reference clock frequency */
	unsigned int			mdio_freq; /* MDIO frequency [Khz] */

	bool up;

	bool				last_link;
	bool				last_establish_failed;
	struct al_eth_lm_context	lm_context;
	bool				use_lm;

	bool				dont_override_serdes; /* avoid overriding serdes parameters
								   to preset static values */
	struct mtx			serdes_config_lock;
	struct mtx			if_rx_lock;

	uint32_t wol;

	struct al_eth_retimer_params	retimer;

	bool				phy_fixup_needed;

	enum al_eth_lm_max_speed	max_speed;
};

#endif /* !(AL_ETH_H) */