#ifndef BCM43xx_DMA_H_
#define BCM43xx_DMA_H_

#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/linkage.h>
#include <asm/atomic.h>


/* DMA-Interrupt reasons. */
#define BCM43xx_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
					 | (1 << 14) | (1 << 15))
#define BCM43xx_DMAIRQ_NONFATALMASK	(1 << 13)
#define BCM43xx_DMAIRQ_RX_DONE		(1 << 16)

/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
#define BCM43xx_DMA_TX_CONTROL		0x00
#define BCM43xx_DMA_TX_DESC_RING	0x04
#define BCM43xx_DMA_TX_DESC_INDEX	0x08
#define BCM43xx_DMA_TX_STATUS		0x0c
#define BCM43xx_DMA_RX_CONTROL		0x10
#define BCM43xx_DMA_RX_DESC_RING	0x14
#define BCM43xx_DMA_RX_DESC_INDEX	0x18
#define BCM43xx_DMA_RX_STATUS		0x1c

/* DMA controller channel control word values. */
#define BCM43xx_DMA_TXCTRL_ENABLE		(1 << 0)
#define BCM43xx_DMA_TXCTRL_SUSPEND		(1 << 1)
#define BCM43xx_DMA_TXCTRL_LOOPBACK		(1 << 2)
#define BCM43xx_DMA_TXCTRL_FLUSH		(1 << 4)
#define BCM43xx_DMA_RXCTRL_ENABLE		(1 << 0)
#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK	0x000000fe
#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT	1
#define BCM43xx_DMA_RXCTRL_PIO			(1 << 8)
/* DMA controller channel status word values. */
#define BCM43xx_DMA_TXSTAT_DPTR_MASK		0x00000fff
#define BCM43xx_DMA_TXSTAT_STAT_MASK		0x0000f000
#define BCM43xx_DMA_TXSTAT_STAT_DISABLED	0x00000000
#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE		0x00001000
#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT	0x00002000
#define BCM43xx_DMA_TXSTAT_STAT_STOPPED		0x00003000
#define BCM43xx_DMA_TXSTAT_STAT_SUSP		0x00004000
#define BCM43xx_DMA_TXSTAT_ERROR_MASK		0x000f0000
#define BCM43xx_DMA_TXSTAT_FLUSHED		(1 << 20)
#define BCM43xx_DMA_RXSTAT_DPTR_MASK		0x00000fff
#define BCM43xx_DMA_RXSTAT_STAT_MASK		0x0000f000
#define BCM43xx_DMA_RXSTAT_STAT_DISABLED	0x00000000
#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE		0x00001000
#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT	0x00002000
#define BCM43xx_DMA_RXSTAT_STAT_RESERVED	0x00003000
#define BCM43xx_DMA_RXSTAT_STAT_ERRORS		0x00004000
#define BCM43xx_DMA_RXSTAT_ERROR_MASK		0x000f0000

/* DMA descriptor control field values. */
#define BCM43xx_DMADTOR_BYTECNT_MASK		0x00001fff
#define BCM43xx_DMADTOR_DTABLEEND		(1 << 28) /* End of descriptor table */
#define BCM43xx_DMADTOR_COMPIRQ			(1 << 29) /* IRQ on completion request */
#define BCM43xx_DMADTOR_FRAMEEND		(1 << 30)
#define BCM43xx_DMADTOR_FRAMESTART		(1 << 31)

/* Misc DMA constants */
#define BCM43xx_DMA_RINGMEMSIZE		PAGE_SIZE
#define BCM43xx_DMA_BUSADDRMAX		0x3FFFFFFF
#define BCM43xx_DMA_DMABUSADDROFFSET	(1 << 30)
#define BCM43xx_DMA1_RX_FRAMEOFFSET	30
#define BCM43xx_DMA4_RX_FRAMEOFFSET	0

/* DMA engine tuning knobs */
#define BCM43xx_TXRING_SLOTS		512
#define BCM43xx_RXRING_SLOTS		64
#define BCM43xx_DMA1_RXBUFFERSIZE	(2304 + 100)
#define BCM43xx_DMA4_RXBUFFERSIZE	16
/* Suspend the tx queue, if less than this percent slots are free. */
#define BCM43xx_TXSUSPEND_PERCENT	20
/* Resume the tx queue, if more than this percent slots are free. */
#define BCM43xx_TXRESUME_PERCENT	50



#ifdef CONFIG_BCM43XX_DMA


struct sk_buff;
struct bcm43xx_private;
struct bcm43xx_xmitstatus;


struct bcm43xx_dmadesc {
	__le32 _control;
	__le32 _address;
} __attribute__((__packed__));

/* Macros to access the bcm43xx_dmadesc struct */
#define get_desc_ctl(desc)		le32_to_cpu((desc)->_control)
#define set_desc_ctl(desc, ctl)		do { (desc)->_control = cpu_to_le32(ctl); } while (0)
#define get_desc_addr(desc)		le32_to_cpu((desc)->_address)
#define set_desc_addr(desc, addr)	do { (desc)->_address = cpu_to_le32(addr); } while (0)

struct bcm43xx_dmadesc_meta {
	/* The kernel DMA-able buffer. */
	struct sk_buff *skb;
	/* DMA base bus-address of the descriptor buffer. */
	dma_addr_t dmaaddr;
};

struct bcm43xx_dmaring {
	struct bcm43xx_private *bcm;
	/* Kernel virtual base address of the ring memory. */
	struct bcm43xx_dmadesc *vbase;
	/* DMA memory offset */
	dma_addr_t memoffset;
	/* (Unadjusted) DMA base bus-address of the ring memory. */
	dma_addr_t dmabase;
	/* Meta data about all descriptors. */
	struct bcm43xx_dmadesc_meta *meta;
	/* Number of descriptor slots in the ring. */
	int nr_slots;
	/* Number of used descriptor slots. */
	int used_slots;
	/* Currently used slot in the ring. */
	int current_slot;
	/* Marks to suspend/resume the queue. */
	int suspend_mark;
	int resume_mark;
	/* Frameoffset in octets. */
	u32 frameoffset;
	/* Descriptor buffer size. */
	u16 rx_buffersize;
	/* The MMIO base register of the DMA controller, this
	 * ring is posted to.
	 */
	u16 mmio_base;
	u8 tx:1,	/* TRUE, if this is a TX ring. */
	   suspended:1;	/* TRUE, if transfers are suspended on this ring. */
#ifdef CONFIG_BCM43XX_DEBUG
	/* Maximum number of used slots. */
	int max_used_slots;
#endif /* CONFIG_BCM43XX_DEBUG*/
};


static inline
u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
		     u16 offset)
{
	return bcm43xx_read32(ring->bcm, ring->mmio_base + offset);
}

static inline
void bcm43xx_dma_write(struct bcm43xx_dmaring *ring,
		       u16 offset, u32 value)
{
	bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value);
}


int bcm43xx_dma_init(struct bcm43xx_private *bcm);
void bcm43xx_dma_free(struct bcm43xx_private *bcm);

int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
				   u16 dmacontroller_mmio_base);
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
				   u16 dmacontroller_mmio_base);

void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);

void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
				   struct bcm43xx_xmitstatus *status);

int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
		   struct ieee80211_txb *txb);
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);


#else /* CONFIG_BCM43XX_DMA */


static inline
int bcm43xx_dma_init(struct bcm43xx_private *bcm)
{
	return 0;
}
static inline
void bcm43xx_dma_free(struct bcm43xx_private *bcm)
{
}
static inline
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
				   u16 dmacontroller_mmio_base)
{
	return 0;
}
static inline
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
				   u16 dmacontroller_mmio_base)
{
	return 0;
}
static inline
int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
		   struct ieee80211_txb *txb)
{
	return 0;
}
static inline
void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
				   struct bcm43xx_xmitstatus *status)
{
}
static inline
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
{
}
static inline
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
{
}
static inline
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
{
}

#endif /* CONFIG_BCM43XX_DMA */
#endif /* BCM43xx_DMA_H_ */
