1193240Ssam/*-
2193240Ssam * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
3193240Ssam * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
4193240Ssam * All rights reserved.
5193240Ssam *
6193240Ssam * Redistribution and use in source and binary forms, with or without
7193240Ssam * modification, are permitted provided that the following conditions
8193240Ssam * are met:
9193240Ssam * 1. Redistributions of source code must retain the above copyright
10193240Ssam *    notice, this list of conditions and the following disclaimer,
11193240Ssam *    without modification.
12193240Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13193240Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
14193240Ssam *    redistribution must be conditioned upon including a substantially
15193240Ssam *    similar Disclaimer requirement for further binary redistribution.
16193240Ssam *
17193240Ssam * NO WARRANTY
18193240Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19193240Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20193240Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
21193240Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22193240Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
23193240Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24193240Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25193240Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26193240Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27193240Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28193240Ssam * THE POSSIBILITY OF SUCH DAMAGES.
29193240Ssam *
30193240Ssam * $FreeBSD$
31193240Ssam */
32193240Ssam
33193240Ssam/*
34193240Ssam * Definitions for the Marvell 88W8363 Wireless LAN controller.
35193240Ssam */
36193240Ssam#ifndef _DEV_MWL_MVVAR_H
37193240Ssam#define _DEV_MWL_MVVAR_H
38193240Ssam
39193240Ssam#include <sys/endian.h>
40298915Sadrian#include <sys/bus.h>
41193240Ssam#include <net80211/ieee80211_radiotap.h>
42193240Ssam#include <dev/mwl/mwlhal.h>
43193240Ssam#include <dev/mwl/mwlreg.h>
44193240Ssam#include <dev/mwl/if_mwlioctl.h>
45193240Ssam
46193240Ssam#ifndef MWL_TXBUF
47193240Ssam#define MWL_TXBUF	256		/* number of TX descriptors/buffers */
48193240Ssam#endif
49195171Ssam#ifndef MWL_TXACKBUF
50195171Ssam#define MWL_TXACKBUF	(MWL_TXBUF/2)	/* number of TX ACK desc's/buffers */
51195171Ssam#endif
52193240Ssam#ifndef MWL_RXDESC
53193240Ssam#define MWL_RXDESC	256		/* number of RX descriptors */
54193240Ssam#endif
55193240Ssam#ifndef MWL_RXBUF
56193240Ssam#define MWL_RXBUF	((5*MWL_RXDESC)/2)/* number of RX dma buffers */
57193240Ssam#endif
58193240Ssam#ifndef MWL_MAXBA
59193240Ssam#define	MWL_MAXBA	2		/* max BA streams/sta */
60193240Ssam#endif
61193240Ssam
62193240Ssam#ifdef MWL_SGDMA_SUPPORT
63193240Ssam#define	MWL_TXDESC	6		/* max tx descriptors/segments */
64193240Ssam#else
65193240Ssam#define	MWL_TXDESC	1		/* max tx descriptors/segments */
66193240Ssam#endif
67193240Ssam#ifndef MWL_AGGR_SIZE
68298955Spfg#define	MWL_AGGR_SIZE	3839		/* max tx aggregation size */
69193240Ssam#endif
70193240Ssam#define	MWL_AGEINTERVAL	1		/* poke f/w every sec to age q's */
71193240Ssam#define	MWL_MAXSTAID	64		/* max of 64 stations */
72193240Ssam
73193240Ssam/*
74193240Ssam * DMA state for tx/rx descriptors.
75193240Ssam */
76193240Ssam
77193240Ssam/*
78193240Ssam * Software backed version of tx/rx descriptors.  We keep
79193240Ssam * the software state out of the h/w descriptor structure
80193240Ssam * so that may be allocated in uncached memory w/o paying
81193240Ssam * performance hit.
82193240Ssam */
83193240Ssamstruct mwl_txbuf {
84193240Ssam	STAILQ_ENTRY(mwl_txbuf) bf_list;
85193240Ssam	void 		*bf_desc;	/* h/w descriptor */
86193240Ssam	bus_addr_t	bf_daddr;	/* physical addr of desc */
87193240Ssam	bus_dmamap_t	bf_dmamap;	/* DMA map for descriptors */
88193240Ssam	int		bf_nseg;
89193240Ssam	bus_dma_segment_t bf_segs[MWL_TXDESC];
90193240Ssam	struct mbuf	*bf_m;
91193240Ssam	struct ieee80211_node *bf_node;
92193240Ssam	struct mwl_txq	*bf_txq;		/* backpointer to tx q/ring */
93193240Ssam};
94193240Ssamtypedef STAILQ_HEAD(, mwl_txbuf) mwl_txbufhead;
95193240Ssam
96193240Ssam/*
97193240Ssam * Common "base class" for tx/rx descriptor resources
98193240Ssam * allocated using the bus dma api.
99193240Ssam */
100193240Ssamstruct mwl_descdma {
101193240Ssam	const char*		dd_name;
102193240Ssam	void			*dd_desc;	/* descriptors */
103193240Ssam	bus_addr_t		dd_desc_paddr;	/* physical addr of dd_desc */
104193240Ssam	bus_size_t		dd_desc_len;	/* size of dd_desc */
105193240Ssam	bus_dma_segment_t	dd_dseg;
106193240Ssam	int			dd_dnseg;	/* number of segments */
107193240Ssam	bus_dma_tag_t		dd_dmat;	/* bus DMA tag */
108193240Ssam	bus_dmamap_t		dd_dmamap;	/* DMA map for descriptors */
109193240Ssam	void			*dd_bufptr;	/* associated buffers */
110193240Ssam};
111193240Ssam
112193240Ssam/*
113193240Ssam * TX/RX ring definitions.  There are 4 tx rings, one
114193240Ssam * per AC, and 1 rx ring.  Note carefully that transmit
115193240Ssam * descriptors are treated as a contiguous chunk and the
116193240Ssam * firmware pre-fetches descriptors.  This means that we
117193240Ssam * must preserve order when moving descriptors between
118193240Ssam * the active+free lists; otherwise we may stall transmit.
119193240Ssam */
120193240Ssamstruct mwl_txq {
121193240Ssam	struct mwl_descdma dma;		/* bus dma resources */
122193240Ssam	struct mtx	lock;		/* tx q lock */
123193240Ssam	char		name[12];	/* e.g. "mwl0_txq4" */
124193240Ssam	int		qnum;		/* f/w q number */
125193240Ssam	int		txpri;		/* f/w tx priority */
126193240Ssam	int		nfree;		/* # buffers on free list */
127193240Ssam	mwl_txbufhead	free;		/* queue of free buffers */
128193240Ssam	mwl_txbufhead	active;		/* queue of active buffers */
129193240Ssam};
130193240Ssam
131193240Ssam#define	MWL_TXQ_LOCK_INIT(_sc, _tq) do { \
132193240Ssam	snprintf((_tq)->name, sizeof((_tq)->name), "%s_txq%u", \
133193240Ssam		device_get_nameunit((_sc)->sc_dev), (_tq)->qnum); \
134193240Ssam	mtx_init(&(_tq)->lock, (_tq)->name, NULL, MTX_DEF); \
135193240Ssam} while (0)
136193240Ssam#define	MWL_TXQ_LOCK_DESTROY(_tq)	mtx_destroy(&(_tq)->lock)
137193240Ssam#define	MWL_TXQ_LOCK(_tq)		mtx_lock(&(_tq)->lock)
138193240Ssam#define	MWL_TXQ_UNLOCK(_tq)		mtx_unlock(&(_tq)->lock)
139193240Ssam#define	MWL_TXQ_LOCK_ASSERT(_tq)	mtx_assert(&(_tq)->lock, MA_OWNED)
140193240Ssam
141193240Ssam#define	MWL_TXDESC_SYNC(txq, ds, how) do { \
142193240Ssam	bus_dmamap_sync((txq)->dma.dd_dmat, (txq)->dma.dd_dmamap, how); \
143193240Ssam} while(0)
144193240Ssam
145193240Ssam/*
146193240Ssam * RX dma buffers that are not in use are kept on a list.
147193240Ssam */
148193240Ssamstruct mwl_jumbo {
149193240Ssam	SLIST_ENTRY(mwl_jumbo) next;
150193240Ssam};
151193240Ssamtypedef SLIST_HEAD(, mwl_jumbo) mwl_jumbohead;
152193240Ssam
153193240Ssam#define	MWL_JUMBO_DATA2BUF(_data)	((struct mwl_jumbo *)(_data))
154193240Ssam#define	MWL_JUMBO_BUF2DATA(_buf)		((uint8_t *)(_buf))
155193240Ssam#define	MWL_JUMBO_OFFSET(_sc, _data) \
156193240Ssam	(((const uint8_t *)(_data)) - (const uint8_t *)((_sc)->sc_rxmem))
157193240Ssam#define	MWL_JUMBO_DMA_ADDR(_sc, _data) \
158193240Ssam	((_sc)->sc_rxmem_paddr + MWL_JUMBO_OFFSET(_sc, _data))
159193240Ssam
160193240Ssamstruct mwl_rxbuf {
161193240Ssam	STAILQ_ENTRY(mwl_rxbuf) bf_list;
162193240Ssam	void 		*bf_desc;	/* h/w descriptor */
163193240Ssam	bus_addr_t	bf_daddr;	/* physical addr of desc */
164193240Ssam	uint8_t		*bf_data;	/* rx data area */
165193240Ssam};
166193240Ssamtypedef STAILQ_HEAD(, mwl_rxbuf) mwl_rxbufhead;
167193240Ssam
168193240Ssam#define	MWL_RXDESC_SYNC(sc, ds, how) do { \
169193240Ssam	bus_dmamap_sync((sc)->sc_rxdma.dd_dmat, (sc)->sc_rxdma.dd_dmamap, how);\
170193240Ssam} while (0)
171193240Ssam
172193240Ssam/*
173193240Ssam * BA stream state.  One of these is setup for each stream
174193240Ssam * allocated/created for use.  We pre-allocate the h/w stream
175193240Ssam * before sending ADDBA request then complete the setup when
176193240Ssam * get ADDBA response (success).  The completed state is setup
177193240Ssam * to optimize the fast path in mwl_txstart--we precalculate
178193240Ssam * the QoS control bits in the outbound frame and use those
179193240Ssam * to identify which BA stream to use (assigning the h/w q to
180193240Ssam * the TxPriority field of the descriptor).
181193240Ssam *
182193240Ssam * NB: Each station may have at most MWL_MAXBA streams at one time.
183193240Ssam */
184193240Ssamstruct mwl_bastate {
185193240Ssam	uint16_t	qos;		/* QoS ctl for BA stream */
186193240Ssam	uint8_t		txq;		/* h/w q for BA stream */
187193240Ssam	const MWL_HAL_BASTREAM *bastream; /* A-MPDU BA stream */
188193240Ssam};
189193240Ssam
190193240Ssamstatic __inline__ void
191234324Sadrianmwl_bastream_setup(struct mwl_bastate *bas, int tid, int txq)
192193240Ssam{
193193240Ssam	bas->txq = txq;
194234324Sadrian	bas->qos = htole16(tid | IEEE80211_QOS_ACKPOLICY_BA);
195193240Ssam}
196193240Ssam
197193240Ssamstatic __inline__ void
198193240Ssammwl_bastream_free(struct mwl_bastate *bas)
199193240Ssam{
200193240Ssam	bas->qos = 0;
201193240Ssam	bas->bastream = NULL;
202193240Ssam	/* NB: don't need to clear txq */
203193240Ssam}
204193240Ssam
205193240Ssam/*
206193240Ssam * Check the QoS control bits from an outbound frame against the
207193240Ssam * value calculated when a BA stream is setup (above).  We need
208193240Ssam * to match the TID and also the ACK policy so we only match AMPDU
209193240Ssam * frames.  The bits from the frame are assumed in network byte
210193240Ssam * order, hence the potential byte swap.
211193240Ssam */
212193240Ssamstatic __inline__ int
213193240Ssammwl_bastream_match(const struct mwl_bastate *bas, uint16_t qos)
214193240Ssam{
215193240Ssam	return (qos & htole16(IEEE80211_QOS_TID|IEEE80211_QOS_ACKPOLICY)) ==
216193240Ssam	    bas->qos;
217193240Ssam}
218193240Ssam
219193240Ssam/* driver-specific node state */
220193240Ssamstruct mwl_node {
221193240Ssam	struct ieee80211_node mn_node;	/* base class */
222193240Ssam	struct mwl_ant_info mn_ai;	/* antenna info */
223193240Ssam	uint32_t	mn_avgrssi;	/* average rssi over all rx frames */
224193240Ssam	uint16_t	mn_staid;	/* firmware station id */
225193240Ssam	struct mwl_bastate mn_ba[MWL_MAXBA];
226193240Ssam	struct mwl_hal_vap *mn_hvap;	/* hal vap handle */
227193240Ssam};
228193240Ssam#define	MWL_NODE(ni)		((struct mwl_node *)(ni))
229193240Ssam#define	MWL_NODE_CONST(ni)	((const struct mwl_node *)(ni))
230193240Ssam
231193240Ssam/*
232193240Ssam * Driver-specific vap state.
233193240Ssam */
234193240Ssamstruct mwl_vap {
235193240Ssam	struct ieee80211vap mv_vap;		/* base class */
236193240Ssam	struct mwl_hal_vap *mv_hvap;		/* hal vap handle */
237193240Ssam	struct mwl_hal_vap *mv_ap_hvap;		/* ap hal vap handle for wds */
238193240Ssam	uint16_t	mv_last_ps_sta;		/* last count of ps sta's */
239193240Ssam	uint16_t	mv_eapolformat;		/* fixed tx rate for EAPOL */
240193240Ssam	int		(*mv_newstate)(struct ieee80211vap *,
241193240Ssam				    enum ieee80211_state, int);
242193240Ssam	int		(*mv_set_tim)(struct ieee80211_node *, int);
243193240Ssam};
244193240Ssam#define	MWL_VAP(vap)	((struct mwl_vap *)(vap))
245193240Ssam#define	MWL_VAP_CONST(vap)	((const struct mwl_vap *)(vap))
246193240Ssam
247193240Ssamstruct mwl_softc {
248287197Sglebius	struct ieee80211com	sc_ic;
249287197Sglebius	struct mbufq		sc_snd;
250193240Ssam	struct mwl_stats	sc_stats;	/* interface statistics */
251193240Ssam	int			sc_debug;
252193240Ssam	device_t		sc_dev;
253193240Ssam	bus_dma_tag_t		sc_dmat;	/* bus DMA tag */
254193240Ssam	bus_space_handle_t	sc_io0h;	/* BAR 0 */
255193240Ssam	bus_space_tag_t		sc_io0t;
256193240Ssam	bus_space_handle_t	sc_io1h;	/* BAR 1 */
257193240Ssam	bus_space_tag_t		sc_io1t;
258193240Ssam	struct mtx		sc_mtx;		/* master lock (recursive) */
259193240Ssam	struct taskqueue	*sc_tq;		/* private task queue */
260199559Sjhb	struct callout	sc_watchdog;
261199559Sjhb	int			sc_tx_timer;
262287197Sglebius	unsigned int		sc_running : 1,
263287197Sglebius				sc_invalid : 1,	/* disable hardware accesses */
264193240Ssam				sc_recvsetup:1,	/* recv setup */
265193240Ssam				sc_csapending:1,/* 11h channel switch pending */
266193240Ssam				sc_radarena : 1,/* radar detection enabled */
267193240Ssam				sc_rxblocked: 1;/* rx waiting for dma buffers */
268193240Ssam
269193240Ssam	struct mwl_hal		*sc_mh;		/* h/w access layer */
270193240Ssam	struct mwl_hal_vap	*sc_hvap;	/* hal vap handle */
271193240Ssam	struct mwl_hal_hwspec	sc_hwspecs;	/* h/w capabilities */
272193240Ssam	uint32_t		sc_fwrelease;	/* release # of loaded f/w */
273193240Ssam	struct mwl_hal_txrxdma	sc_hwdma;	/* h/w dma setup */
274193240Ssam	uint32_t		sc_imask;	/* interrupt mask copy */
275193240Ssam	enum ieee80211_phymode	sc_curmode;
276193240Ssam	u_int16_t		sc_curaid;	/* current association id */
277193240Ssam	u_int8_t		sc_curbssid[IEEE80211_ADDR_LEN];
278193240Ssam	MWL_HAL_CHANNEL		sc_curchan;
279193240Ssam	MWL_HAL_TXRATE_HANDLING	sc_txratehandling;
280193240Ssam	u_int16_t		sc_rxantenna;	/* rx antenna */
281193240Ssam	u_int16_t		sc_txantenna;	/* tx antenna */
282193240Ssam	uint8_t			sc_napvaps;	/* # ap mode vaps */
283193240Ssam	uint8_t			sc_nwdsvaps;	/* # wds mode vaps */
284193240Ssam	uint8_t			sc_nstavaps;	/* # sta mode vaps */
285195171Ssam	uint8_t			sc_ndwdsvaps;	/* # sta mode dwds vaps */
286193240Ssam	uint8_t			sc_nbssid0;	/* # vap's using base mac */
287193240Ssam	uint32_t		sc_bssidmask;	/* bssid mask */
288193240Ssam
289193240Ssam	void			(*sc_recv_mgmt)(struct ieee80211com *,
290193240Ssam				    struct mbuf *,
291193240Ssam				    struct ieee80211_node *,
292193240Ssam				    int, int, int, u_int32_t);
293193240Ssam	int			(*sc_newstate)(struct ieee80211com *,
294193240Ssam				    enum ieee80211_state, int);
295193240Ssam	void 			(*sc_node_cleanup)(struct ieee80211_node *);
296193240Ssam	void 			(*sc_node_drain)(struct ieee80211_node *);
297195377Ssam	int			(*sc_recv_action)(struct ieee80211_node *,
298195377Ssam				    const struct ieee80211_frame *,
299193240Ssam				    const uint8_t *, const uint8_t *);
300193240Ssam	int			(*sc_addba_request)(struct ieee80211_node *,
301193240Ssam				    struct ieee80211_tx_ampdu *,
302193240Ssam				    int dialogtoken, int baparamset,
303193240Ssam				    int batimeout);
304193240Ssam	int			(*sc_addba_response)(struct ieee80211_node *,
305193240Ssam				    struct ieee80211_tx_ampdu *,
306193240Ssam				    int status, int baparamset,
307193240Ssam				    int batimeout);
308193240Ssam	void			(*sc_addba_stop)(struct ieee80211_node *,
309193240Ssam				    struct ieee80211_tx_ampdu *);
310193240Ssam
311193240Ssam	struct mwl_descdma	sc_rxdma;	/* rx bus dma resources */
312193240Ssam	mwl_rxbufhead		sc_rxbuf;	/* rx buffers */
313193240Ssam	struct mwl_rxbuf	*sc_rxnext;	/* next rx buffer to process */
314193240Ssam	struct task		sc_rxtask;	/* rx int processing */
315193240Ssam	void			*sc_rxmem;	/* rx dma buffer pool */
316193240Ssam	bus_dma_tag_t		sc_rxdmat;	/* rx bus DMA tag */
317193240Ssam	bus_size_t		sc_rxmemsize;	/* rx dma buffer pool size */
318193240Ssam	bus_dmamap_t		sc_rxmap;	/* map for rx dma buffers */
319193240Ssam	bus_addr_t		sc_rxmem_paddr;	/* physical addr of sc_rxmem */
320193240Ssam	mwl_jumbohead		sc_rxfree;	/* list of free dma buffers */
321193240Ssam	int			sc_nrxfree;	/* # buffers on rx free list */
322193240Ssam	struct mtx		sc_rxlock;	/* lock on sc_rxfree */
323193240Ssam
324193240Ssam	struct mwl_txq		sc_txq[MWL_NUM_TX_QUEUES];
325193240Ssam	struct mwl_txq		*sc_ac2q[5];	/* WME AC -> h/w q map */
326193240Ssam	struct mbuf		*sc_aggrq;	/* aggregation q */
327193240Ssam	struct task		sc_txtask;	/* tx int processing */
328193240Ssam	struct task		sc_bawatchdogtask;/* BA watchdog processing */
329193240Ssam
330193240Ssam	struct task		sc_radartask;	/* radar detect processing */
331193240Ssam	struct task		sc_chanswitchtask;/* chan switch processing */
332193240Ssam
333193240Ssam	uint8_t			sc_staid[MWL_MAXSTAID/NBBY];
334193240Ssam	int			sc_ageinterval;
335193240Ssam	struct callout		sc_timer;	/* periodic work */
336193240Ssam
337193240Ssam	struct mwl_tx_radiotap_header sc_tx_th;
338193240Ssam	struct mwl_rx_radiotap_header sc_rx_th;
339193240Ssam};
340193240Ssam
341193240Ssam#define	MWL_LOCK_INIT(_sc) \
342193240Ssam	mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
343193240Ssam		 NULL, MTX_DEF | MTX_RECURSE)
344193240Ssam#define	MWL_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_mtx)
345193240Ssam#define	MWL_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
346193240Ssam#define	MWL_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
347193240Ssam#define	MWL_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
348193240Ssam
349193240Ssam#define	MWL_RXFREE_INIT(_sc) \
350193240Ssam	mtx_init(&(_sc)->sc_rxlock, device_get_nameunit((_sc)->sc_dev), \
351193240Ssam		 NULL, MTX_DEF)
352193240Ssam#define	MWL_RXFREE_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_rxlock)
353193240Ssam#define	MWL_RXFREE_LOCK(_sc)	mtx_lock(&(_sc)->sc_rxlock)
354193240Ssam#define	MWL_RXFREE_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_rxlock)
355193240Ssam#define	MWL_RXFREE_ASSERT(_sc)	mtx_assert(&(_sc)->sc_rxlock, MA_OWNED)
356193240Ssam
357193240Ssamint	mwl_attach(u_int16_t, struct mwl_softc *);
358193240Ssamint	mwl_detach(struct mwl_softc *);
359193240Ssamvoid	mwl_resume(struct mwl_softc *);
360193240Ssamvoid	mwl_suspend(struct mwl_softc *);
361193240Ssamvoid	mwl_shutdown(void *);
362193240Ssamvoid	mwl_intr(void *);
363193240Ssam
364193240Ssam#endif /* _DEV_MWL_MVVAR_H */
365