1143392Ssam/*-
2143392Ssam * Copyright (c) 2005 John Bicket
3143392Ssam * All rights reserved.
4143392Ssam *
5143392Ssam * Redistribution and use in source and binary forms, with or without
6143392Ssam * modification, are permitted provided that the following conditions
7143392Ssam * are met:
8143392Ssam * 1. Redistributions of source code must retain the above copyright
9143392Ssam *    notice, this list of conditions and the following disclaimer,
10143392Ssam *    without modification.
11143392Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12143392Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13143392Ssam *    redistribution must be conditioned upon including a substantially
14143392Ssam *    similar Disclaimer requirement for further binary redistribution.
15143392Ssam * 3. Neither the names of the above-listed copyright holders nor the names
16143392Ssam *    of any contributors may be used to endorse or promote products derived
17143392Ssam *    from this software without specific prior written permission.
18143392Ssam *
19143392Ssam * Alternatively, this software may be distributed under the terms of the
20143392Ssam * GNU General Public License ("GPL") version 2 as published by the Free
21143392Ssam * Software Foundation.
22143392Ssam *
23143392Ssam * NO WARRANTY
24143392Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25143392Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26143392Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27143392Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28143392Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29143392Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30143392Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31143392Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32143392Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33143392Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34143392Ssam * THE POSSIBILITY OF SUCH DAMAGES.
35143392Ssam *
36143392Ssam * $FreeBSD$
37143392Ssam */
38143392Ssam
39143392Ssam/*
40143392Ssam * Defintions for the Atheros Wireless LAN controller driver.
41143392Ssam */
42143392Ssam#ifndef _DEV_ATH_RATE_SAMPLE_H
43143392Ssam#define _DEV_ATH_RATE_SAMPLE_H
44143392Ssam
45143392Ssam/* per-device state */
46143392Ssamstruct sample_softc {
47185482Ssam	struct ath_ratectrl arc;	/* base class */
48185482Ssam	int	smoothing_rate;		/* ewma percentage [0..99] */
49185482Ssam	int	smoothing_minpackets;
50185482Ssam	int	sample_rate;		/* %time to try different tx rates */
51185482Ssam	int	max_successive_failures;
52185482Ssam	int	stale_failure_timeout;	/* how long to honor max_successive_failures */
53185482Ssam	int	min_switch;		/* min time between rate changes */
54227364Sadrian	int	min_good_pct;		/* min good percentage for a rate to be considered */
55143392Ssam};
56143392Ssam#define	ATH_SOFTC_SAMPLE(sc)	((struct sample_softc *)sc->sc_rc)
57143392Ssam
58143392Ssamstruct rate_stats {
59143853Ssam	unsigned average_tx_time;
60143392Ssam	int successive_failures;
61227340Sadrian	uint64_t tries;
62227340Sadrian	uint64_t total_packets;	/* pkts total since assoc */
63227340Sadrian	uint64_t packets_acked;	/* pkts acked since assoc */
64227364Sadrian	int ewma_pct;	/* EWMA percentage */
65143853Ssam	unsigned perfect_tx_time; /* transmit time for 0 retries */
66143392Ssam	int last_tx;
67143392Ssam};
68143392Ssam
69185482Ssamstruct txschedule {
70185482Ssam	uint8_t	t0, r0;		/* series 0: tries, rate code */
71185482Ssam	uint8_t	t1, r1;		/* series 1: tries, rate code */
72185482Ssam	uint8_t	t2, r2;		/* series 2: tries, rate code */
73185482Ssam	uint8_t	t3, r3;		/* series 3: tries, rate code */
74185482Ssam};
75185482Ssam
76143392Ssam/*
77143392Ssam * for now, we track performance for three different packet
78143392Ssam * size buckets
79143392Ssam */
80185482Ssam#define NUM_PACKET_SIZE_BINS 2
81143392Ssam
82238633Sadrianstatic const int packet_size_bins[NUM_PACKET_SIZE_BINS]  = { 250, 1600 };
83238633Sadrian
84238633Sadrianstatic inline int
85238633Sadrianbin_to_size(int index)
86238633Sadrian{
87238633Sadrian	return packet_size_bins[index];
88238633Sadrian}
89238633Sadrian
90143392Ssam/* per-node state */
91143392Ssamstruct sample_node {
92185482Ssam	int static_rix;			/* rate index of fixed tx rate */
93238636Sadrian#define	SAMPLE_MAXRATES	64		/* NB: corresponds to hal info[32] */
94239284Sadrian	uint64_t ratemask;		/* bit mask of valid rate indices */
95185482Ssam	const struct txschedule *sched;	/* tx schedule table */
96143392Ssam
97232170Sadrian	const HAL_RATE_TABLE *currates;
98232170Sadrian
99185482Ssam	struct rate_stats stats[NUM_PACKET_SIZE_BINS][SAMPLE_MAXRATES];
100185482Ssam	int last_sample_rix[NUM_PACKET_SIZE_BINS];
101143853Ssam
102185482Ssam	int current_sample_rix[NUM_PACKET_SIZE_BINS];
103143392Ssam	int packets_sent[NUM_PACKET_SIZE_BINS];
104143392Ssam
105185482Ssam	int current_rix[NUM_PACKET_SIZE_BINS];
106143853Ssam	int packets_since_switch[NUM_PACKET_SIZE_BINS];
107155476Ssam	unsigned ticks_since_switch[NUM_PACKET_SIZE_BINS];
108143853Ssam
109143853Ssam	int packets_since_sample[NUM_PACKET_SIZE_BINS];
110143853Ssam	unsigned sample_tt[NUM_PACKET_SIZE_BINS];
111143392Ssam};
112238630Sadrian
113238630Sadrian#ifdef	_KERNEL
114238630Sadrian
115185482Ssam#define	ATH_NODE_SAMPLE(an)	((struct sample_node *)&(an)[1])
116185482Ssam#define	IS_RATE_DEFINED(sn, rix)	(((sn)->ratemask & (1<<(rix))) != 0)
117143392Ssam
118143392Ssam#ifndef MIN
119143392Ssam#define	MIN(a,b)	((a) < (b) ? (a) : (b))
120143392Ssam#endif
121143392Ssam#ifndef MAX
122143392Ssam#define	MAX(a,b)	((a) > (b) ? (a) : (b))
123143392Ssam#endif
124143392Ssam
125143392Ssam#define WIFI_CW_MIN 31
126143392Ssam#define WIFI_CW_MAX 1023
127143392Ssam
128165185Ssam/*
129143392Ssam * Calculate the transmit duration of a frame.
130143392Ssam */
131143392Ssamstatic unsigned calc_usecs_unicast_packet(struct ath_softc *sc,
132218448Sadrian				int length,
133218761Sadrian				int rix, int short_retries,
134218761Sadrian				int long_retries, int is_ht40)
135218761Sadrian{
136143392Ssam	const HAL_RATE_TABLE *rt = sc->sc_currates;
137178354Ssam	struct ifnet *ifp = sc->sc_ifp;
138178354Ssam	struct ieee80211com *ic = ifp->if_l2com;
139155476Ssam	int rts, cts;
140143392Ssam
141143392Ssam	unsigned t_slot = 20;
142143392Ssam	unsigned t_difs = 50;
143143392Ssam	unsigned t_sifs = 10;
144143392Ssam	int tt = 0;
145143392Ssam	int x = 0;
146143392Ssam	int cw = WIFI_CW_MIN;
147165185Ssam	int cix;
148143862Ssam
149143392Ssam	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
150143862Ssam
151165185Ssam	if (rix >= rt->rateCount) {
152165185Ssam		printf("bogus rix %d, max %u, mode %u\n",
153165185Ssam		       rix, rt->rateCount, sc->sc_curmode);
154155476Ssam		return 0;
155155476Ssam	}
156165185Ssam	cix = rt->info[rix].controlRate;
157155476Ssam	/*
158155476Ssam	 * XXX getting mac/phy level timings should be fixed for turbo
159155476Ssam	 * rates, and there is probably a way to get this from the
160155476Ssam	 * hal...
161155476Ssam	 */
162155476Ssam	switch (rt->info[rix].phy) {
163155476Ssam	case IEEE80211_T_OFDM:
164143392Ssam		t_slot = 9;
165155476Ssam		t_sifs = 16;
166143392Ssam		t_difs = 28;
167155476Ssam		/* fall through */
168155476Ssam	case IEEE80211_T_TURBO:
169155476Ssam		t_slot = 9;
170155476Ssam		t_sifs = 8;
171155476Ssam		t_difs = 28;
172155476Ssam		break;
173218448Sadrian	case IEEE80211_T_HT:
174218448Sadrian		t_slot = 9;
175218448Sadrian		t_sifs = 8;
176218448Sadrian		t_difs = 28;
177218448Sadrian		break;
178155476Ssam	case IEEE80211_T_DS:
179155476Ssam		/* fall through to default */
180155476Ssam	default:
181155476Ssam		/* pg 205 ieee.802.11.pdf */
182155476Ssam		t_slot = 20;
183155476Ssam		t_difs = 50;
184155476Ssam		t_sifs = 10;
185143392Ssam	}
186143853Ssam
187155476Ssam	rts = cts = 0;
188155476Ssam
189143853Ssam	if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
190143853Ssam	    rt->info[rix].phy == IEEE80211_T_OFDM) {
191143853Ssam		if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
192143853Ssam			rts = 1;
193143853Ssam		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
194143853Ssam			cts = 1;
195143853Ssam
196143853Ssam		cix = rt->info[sc->sc_protrix].controlRate;
197143853Ssam	}
198143853Ssam
199155476Ssam	if (0 /*length > ic->ic_rtsthreshold */) {
200143853Ssam		rts = 1;
201143853Ssam	}
202143853Ssam
203143853Ssam	if (rts || cts) {
204165185Ssam		int ctsrate;
205143853Ssam		int ctsduration = 0;
206155476Ssam
207165185Ssam		/* NB: this is intentionally not a runtime check */
208165185Ssam		KASSERT(cix < rt->rateCount,
209165185Ssam		    ("bogus cix %d, max %u, mode %u\n", cix, rt->rateCount,
210165185Ssam		     sc->sc_curmode));
211155476Ssam
212165185Ssam		ctsrate = rt->info[cix].rateCode | rt->info[cix].shortPreamble;
213143853Ssam		if (rts)		/* SIFS + CTS */
214143853Ssam			ctsduration += rt->info[cix].spAckDuration;
215143853Ssam
216218448Sadrian		/* XXX assumes short preamble */
217225473Sadrian		ctsduration += ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix,
218225473Sadrian		    is_ht40, 0);
219143853Ssam
220143853Ssam		if (cts)	/* SIFS + ACK */
221143853Ssam			ctsduration += rt->info[cix].spAckDuration;
222143853Ssam
223143853Ssam		tt += (short_retries + 1) * ctsduration;
224143853Ssam	}
225143392Ssam	tt += t_difs;
226218448Sadrian
227218448Sadrian	/* XXX assumes short preamble */
228225473Sadrian	tt += (long_retries+1)*ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix,
229225473Sadrian	    is_ht40, 0);
230225473Sadrian
231155476Ssam	tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration);
232218448Sadrian
233143853Ssam	for (x = 0; x <= short_retries + long_retries; x++) {
234143392Ssam		cw = MIN(WIFI_CW_MAX, (cw + 1) * 2);
235143392Ssam		tt += (t_slot * cw/2);
236143392Ssam	}
237143392Ssam	return tt;
238143392Ssam}
239238630Sadrian
240238630Sadrian#endif	/* _KERNEL */
241238630Sadrian
242143392Ssam#endif /* _DEV_ATH_RATE_SAMPLE_H */
243