/*-
 * Copyright (c) 2001-2003
 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
 * 	All rights reserved.
 *
 * 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.
 *
 * Author: Hartmut Brandt <harti@freebsd.org>
 *
 * $FreeBSD: release/9.2.0/sys/dev/fatm/if_fatmvar.h 199559 2009-11-19 22:06:40Z jhb $
 *
 * Fore PCA200E driver definitions.
 */
/*
 * Debug statistics of the PCA200 driver
 */
struct istats {
	uint32_t	cmd_queue_full;
	uint32_t	get_stat_errors;
	uint32_t	clr_stat_errors;
	uint32_t	get_prom_errors;
	uint32_t	suni_reg_errors;
	uint32_t	tx_queue_full;
	uint32_t	tx_queue_almost_full;
	uint32_t	tx_pdu2big;
	uint32_t	tx_too_many_segs;
	uint32_t	tx_retry;
	uint32_t	fix_empty;
	uint32_t	fix_addr_copy;
	uint32_t	fix_addr_noext;
	uint32_t	fix_addr_ext;
	uint32_t	fix_len_noext;
	uint32_t	fix_len_copy;
	uint32_t	fix_len;
	uint32_t	rx_badvc;
	uint32_t	rx_closed;
};

/*
 * Addresses on the on-board RAM are expressed as offsets to the
 * start of that RAM.
 */
typedef uint32_t cardoff_t;

/*
 * The card uses a number of queues for communication with the host.
 * Parts of the queue are located on the card (pointers to the status
 * word and the ioblk and the command blocks), the rest in host memory.
 * Each of these queues forms a ring, where the head and tail pointers are
 * managed * either by the card or the host. For the receive queue the
 * head is managed by the card (and not used altogether by the host) and the
 * tail by the host - for all other queues its the other way around.
 * The host resident parts of the queue entries contain pointers to
 * the host resident status and the host resident ioblk (the latter not for
 * the command queue) as well as DMA addresses for supply to the card.
 */
struct fqelem {
	cardoff_t	card;		/* corresponding element on card */
	bus_addr_t	card_ioblk;	/* ioblk address to supply to card */
	volatile uint32_t *statp;		/* host status pointer */
	void		*ioblk;		/* host ioblk (not for commands) */
};

struct fqueue {
	struct fqelem	*chunk;		/* pointer to the element array */
	int		head;		/* queue head */
	int		tail;		/* queue tail */
};

/*
 * Queue manipulation macros
 */
#define	NEXT_QUEUE_ENTRY(HEAD,LEN) ((HEAD) = ((HEAD) + 1) % LEN)
#define	GET_QUEUE(Q,TYPE,IDX)    (&((TYPE *)(Q).chunk)[(IDX)])

/*
 * Now define structures for the different queues. Each of these structures
 * must start with a struct fqelem.
 */
struct txqueue {		/* transmit queue element */
	struct fqelem	q;
	struct mbuf	*m;	/* the chain we are transmitting */
	bus_dmamap_t	map;	/* map for the packet */
};

struct rxqueue {		/* receive queue element */
	struct fqelem	q;
};

struct supqueue {		/* supply queue element */
	struct fqelem	q;
};

struct cmdqueue;
struct fatm_softc;

typedef void (*completion_cb)(struct fatm_softc *, struct cmdqueue *);

struct cmdqueue {		/* command queue element */
	struct fqelem	q;
	completion_cb	cb;	/* call on command completion */
	int		error;	/* set if error occured */
};

/*
 * Card-DMA-able memory is managed by means of the bus_dma* functions.
 * To allocate a chunk of memory with a specific size and alignment one
 * has to:
 *	1. create a DMA tag
 *	2. allocate the memory
 *	3. load the memory into a map.
 * This finally gives the physical address that can be given to the card.
 * The card can DMA the entire 32-bit space without boundaries. We assume,
 * that all the allocations can be mapped in one contiguous segment. This
 * may be wrong in the future if we have more than 32 bit addresses.
 * Allocation is done at attach time and managed by the following structure.
 *
 * This could be done easier with the NetBSD bus_dma* functions. They appear
 * to be more useful and consistent.
 */
struct fatm_mem {
	u_int		size;		/* size */
	u_int		align;		/* alignment */
	bus_dma_tag_t	dmat;		/* DMA tag */
	void 		*mem;		/* memory block */
	bus_addr_t	paddr;		/* pysical address */
	bus_dmamap_t	map;		/* map */
};

/*
 * Each of these structures describes one receive buffer while the buffer
 * is on the card or in the receive return queue. These structures are
 * allocated at initialisation time together with the DMA maps. The handle that
 * is given to the card is the index into the array of these structures.
 */
struct rbuf {
	struct mbuf	*m;	/* the mbuf while we are on the card */
	bus_dmamap_t	map;	/* the map */
	LIST_ENTRY(rbuf) link;	/* the free list link */
};
LIST_HEAD(rbuf_list, rbuf);

/*
 * The driver maintains a list of all open VCCs. Because we
 * use only VPI=0 and a maximum VCI of 1024, the list is rather an array
 * than a list. We also store the atm pseudoheader flags here and the
 * rxhand (aka. protocol block).
 */
struct card_vcc {
	struct atmio_vcc param;		/* traffic parameters */
	void		*rxhand;
	u_int		vflags;
	uint32_t	ipackets;
	uint32_t	opackets;
	uint32_t	ibytes;
	uint32_t	obytes;
};

#define	FATM_VCC_OPEN		0x00010000	/* is open */
#define	FATM_VCC_TRY_OPEN	0x00020000	/* is currently opening */
#define	FATM_VCC_TRY_CLOSE	0x00040000	/* is currently closing */
#define	FATM_VCC_BUSY		0x00070000	/* one of the above */
#define	FATM_VCC_REOPEN		0x00080000	/* reopening during init */

/*
 * Finally the softc structure
 */
struct fatm_softc {
	struct ifnet	*ifp;		/* common part */
	struct mtx	mtx;		/* lock this structure */
	struct ifmedia	media;		/* media */
	struct callout	watchdog_timer;

	int		init_state;	/* initialisation step */
	int		memid;		/* resource id for card memory */
	struct resource *memres;	/* resource for card memory */
	bus_space_handle_t memh;	/* handle for card memory */
	bus_space_tag_t	memt;		/* tag for card memory */
	int		irqid;		/* resource id for interrupt */
	struct resource *irqres;	/* resource for interrupt */
	void		*ih;		/* interrupt handler */

	bus_dma_tag_t	parent_dmat;	/* parent DMA tag */
	struct fatm_mem	stat_mem;	/* memory for status blocks */
	struct fatm_mem	txq_mem;	/* TX descriptor queue */
	struct fatm_mem	rxq_mem;	/* RX descriptor queue */
	struct fatm_mem	s1q_mem;	/* Small buffer 1 queue */
	struct fatm_mem	l1q_mem;	/* Large buffer 1 queue */
	struct fatm_mem	prom_mem;	/* PROM memory */

	struct fqueue	txqueue;	/* transmission queue */
	struct fqueue	rxqueue;	/* receive queue */
	struct fqueue	s1queue;	/* SMALL S1 queue */
	struct fqueue	l1queue;	/* LARGE S1 queue */
	struct fqueue	cmdqueue;	/* command queue */

	/* fields for access to the SUNI registers */
	struct fatm_mem	reg_mem;	/* DMAable memory for readregs */
	struct cv	cv_regs;	/* to serialize access to reg_mem */

	/* fields for access to statistics */
	struct fatm_mem	sadi_mem;	/* sadistics memory */
	struct cv	cv_stat;	/* to serialize access to sadi_mem */

	u_int		flags;
#define	FATM_STAT_INUSE	0x0001
#define	FATM_REGS_INUSE	0x0002
	u_int		txcnt;		/* number of used transmit desc */
	int		retry_tx;	/* keep mbufs in queue if full */

	struct card_vcc	**vccs;		/* table of vccs */
	int		open_vccs;	/* number of vccs in use */
	int		small_cnt;	/* number of buffers owned by card */
	int		large_cnt;	/* number of buffers owned by card */
	uma_zone_t	vcc_zone;	/* allocator for VCCs */

	/* receiving */
	struct rbuf	*rbufs;		/* rbuf array */
	struct rbuf_list rbuf_free;	/* free rbufs list */
	struct rbuf_list rbuf_used;	/* used rbufs list */
	u_int		rbuf_total;	/* total number of buffs */
	bus_dma_tag_t	rbuf_tag;	/* tag for rbuf mapping */

	/* transmission */
	bus_dma_tag_t	tx_tag;		/* transmission tag */

	uint32_t	heartbeat;	/* last heartbeat */
	u_int		stop_cnt;	/* how many times checked */

	struct istats	istats;		/* internal statistics */

	/* SUNI state */
	struct utopia	utopia;

	/* sysctl support */
	struct sysctl_ctx_list sysctl_ctx;
	struct sysctl_oid *sysctl_tree;

#ifdef FATM_DEBUG
	/* debugging */
	u_int		debug;
#endif
};

#ifndef FATM_DEBUG
#define	FATM_LOCK(SC)		mtx_lock(&(SC)->mtx)
#define	FATM_UNLOCK(SC)		mtx_unlock(&(SC)->mtx)
#else
#define	FATM_LOCK(SC)	do {					\
	DBG(SC, LOCK, ("locking in line %d", __LINE__));	\
	mtx_lock(&(SC)->mtx);					\
    } while (0)
#define	FATM_UNLOCK(SC)	do {					\
	DBG(SC, LOCK, ("unlocking in line %d", __LINE__));	\
	mtx_unlock(&(SC)->mtx);					\
    } while (0)
#endif
#define	FATM_CHECKLOCK(SC)	mtx_assert(&sc->mtx, MA_OWNED)

/*
 * Macros to access host memory fields that are also access by the card.
 * These fields need to little-endian always.
 */
#define	H_GETSTAT(STATP)	(le32toh(*(STATP)))
#define	H_SETSTAT(STATP, S)	do { *(STATP) = htole32(S); } while (0)
#define	H_SETDESC(DESC, D)	do { (DESC) = htole32(D); } while (0)

#ifdef notyet
#define	H_SYNCSTAT_POSTREAD(SC, P)					\
	bus_dmamap_sync_size((SC)->stat_mem.dmat,			\
	    (SC)->stat_mem.map,						\
	    (volatile char *)(P) - (volatile char *)(SC)->stat_mem.mem,	\
	    sizeof(volatile uint32_t), BUS_DMASYNC_POSTREAD)

#define	H_SYNCSTAT_PREWRITE(SC, P)					\
	bus_dmamap_sync_size((SC)->stat_mem.dmat,			\
	    (SC)->stat_mem.map,						\
	    (volatile char *)(P) - (volatile char *)(SC)->stat_mem.mem,	\
	    sizeof(volatile uint32_t), BUS_DMASYNC_PREWRITE)

#define	H_SYNCQ_PREWRITE(M, P, SZ)					\
	bus_dmamap_sync_size((M)->dmat, (M)->map,			\
	    (volatile char *)(P) - (volatile char *)(M)->mem, (SZ),	\
	    BUS_DMASYNC_PREWRITE)

#define	H_SYNCQ_POSTREAD(M, P, SZ)					\
	bus_dmamap_sync_size((M)->dmat, (M)->map,			\
	    (volatile char *)(P) - (volatile char *)(M)->mem, (SZ),	\
	    BUS_DMASYNC_POSTREAD)
#else
#define	H_SYNCSTAT_POSTREAD(SC, P)	do { } while (0)
#define	H_SYNCSTAT_PREWRITE(SC, P)	do { } while (0)
#define	H_SYNCQ_PREWRITE(M, P, SZ)	do { } while (0)
#define	H_SYNCQ_POSTREAD(M, P, SZ)	do { } while (0)
#endif

/*
 * Macros to manipulate VPVCs
 */
#define	MKVPVC(VPI,VCI)	(((VPI) << 16) | (VCI))
#define	GETVPI(VPVC)		(((VPVC) >> 16) & 0xff)
#define	GETVCI(VPVC)		((VPVC) & 0xffff)

/*
 * These macros encapsulate the bus_space functions for better readabiliy.
 */
#define	WRITE4(SC, OFF, VAL) bus_space_write_4(SC->memt, SC->memh, OFF, VAL)
#define	WRITE1(SC, OFF, VAL) bus_space_write_1(SC->memt, SC->memh, OFF, VAL)

#define	READ4(SC, OFF) bus_space_read_4(SC->memt, SC->memh, OFF)
#define	READ1(SC, OFF) bus_space_read_1(SC->memt, SC->memh, OFF)

#define	BARRIER_R(SC) \
	bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
	    BUS_SPACE_BARRIER_READ)
#define	BARRIER_W(SC) \
	bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
	    BUS_SPACE_BARRIER_WRITE)
#define	BARRIER_RW(SC) \
	bus_space_barrier(SC->memt, SC->memh, 0, FATMO_END, \
	    BUS_SPACE_BARRIER_WRITE|BUS_SPACE_BARRIER_READ)

#ifdef FATM_DEBUG
#define	DBG(SC, FL, PRINT) do {						\
	if ((SC)->debug & DBG_##FL) { 					\
		if_printf(&(SC)->ifatm.ifnet, "%s: ", __func__);	\
		printf PRINT;						\
		printf("\n");						\
	}								\
    } while (0)
#define	DBGC(SC, FL, PRINT) do {					\
	if ((SC)->debug & DBG_##FL) 					\
		printf PRINT;						\
    } while (0)

enum {
	DBG_RCV		= 0x0001,
	DBG_XMIT	= 0x0002,
	DBG_VCC		= 0x0004,
	DBG_IOCTL	= 0x0008,
	DBG_ATTACH	= 0x0010,
	DBG_INIT	= 0x0020,
	DBG_DMA		= 0x0040,
	DBG_BEAT	= 0x0080,
	DBG_UART	= 0x0100,
	DBG_LOCK	= 0x0200,

	DBG_ALL		= 0xffff
};

#else
#define	DBG(SC, FL, PRINT)
#define	DBGC(SC, FL, PRINT)
#endif

/*
 * Configuration.
 *
 * This section contains tunable parameters and dependend defines.
 */
#define	FATM_CMD_QLEN		16		/* command queue length */
#ifndef TEST_DMA_SYNC
#define	FATM_TX_QLEN		128		/* transmit queue length */
#define	FATM_RX_QLEN		64		/* receive queue length */
#else
#define	FATM_TX_QLEN		8		/* transmit queue length */
#define	FATM_RX_QLEN		8		/* receive queue length */
#endif

#define	SMALL_SUPPLY_QLEN	16
#define	SMALL_POOL_SIZE		256
#define	SMALL_SUPPLY_BLKSIZE	8

#define	LARGE_SUPPLY_QLEN	16
#define	LARGE_POOL_SIZE		128
#define	LARGE_SUPPLY_BLKSIZE	8
