diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2009-11-30 03:18:19 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-21 18:55:55 -0500 |
commit | 86dff7a7955f1e14c1f2c142312462fae70ea7e4 (patch) | |
tree | 04b4401a2c8467dcbf00e219c2b222ff45cf20b8 /drivers/net/wireless | |
parent | cdd1e9a91ea55594cbcc9847dbb9392e341cbefd (diff) |
wl1251: implement acx_ac_cfg to configure hardware queues
Needed for WMM.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Reviewed-by: Janne Ylalehto <janne.ylalehto@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_acx.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_acx.h | 32 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_init.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_init.h | 47 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_tx.h | 20 |
6 files changed, 164 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index acfa086dbfc..b409c75499d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c | |||
@@ -976,3 +976,36 @@ out: | |||
976 | kfree(acx); | 976 | kfree(acx); |
977 | return ret; | 977 | return ret; |
978 | } | 978 | } |
979 | |||
980 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
981 | u8 aifs, u16 txop) | ||
982 | { | ||
983 | struct wl1251_acx_ac_cfg *acx; | ||
984 | int ret = 0; | ||
985 | |||
986 | wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " | ||
987 | "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); | ||
988 | |||
989 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
990 | |||
991 | if (!acx) { | ||
992 | ret = -ENOMEM; | ||
993 | goto out; | ||
994 | } | ||
995 | |||
996 | acx->ac = ac; | ||
997 | acx->cw_min = cw_min; | ||
998 | acx->cw_max = cw_max; | ||
999 | acx->aifsn = aifs; | ||
1000 | acx->txop_limit = txop; | ||
1001 | |||
1002 | ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
1003 | if (ret < 0) { | ||
1004 | wl1251_warning("acx ac cfg failed: %d", ret); | ||
1005 | goto out; | ||
1006 | } | ||
1007 | |||
1008 | out: | ||
1009 | kfree(acx); | ||
1010 | return ret; | ||
1011 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 652371432cd..56793245b28 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h | |||
@@ -1166,6 +1166,36 @@ struct wl1251_acx_wr_tbtt_and_dtim { | |||
1166 | u8 padding; | 1166 | u8 padding; |
1167 | } __attribute__ ((packed)); | 1167 | } __attribute__ ((packed)); |
1168 | 1168 | ||
1169 | struct wl1251_acx_ac_cfg { | ||
1170 | struct acx_header header; | ||
1171 | |||
1172 | /* | ||
1173 | * Access Category - The TX queue's access category | ||
1174 | * (refer to AccessCategory_enum) | ||
1175 | */ | ||
1176 | u8 ac; | ||
1177 | |||
1178 | /* | ||
1179 | * The contention window minimum size (in slots) for | ||
1180 | * the access class. | ||
1181 | */ | ||
1182 | u8 cw_min; | ||
1183 | |||
1184 | /* | ||
1185 | * The contention window maximum size (in slots) for | ||
1186 | * the access class. | ||
1187 | */ | ||
1188 | u16 cw_max; | ||
1189 | |||
1190 | /* The AIF value (in slots) for the access class. */ | ||
1191 | u8 aifsn; | ||
1192 | |||
1193 | u8 reserved; | ||
1194 | |||
1195 | /* The TX Op Limit (in microseconds) for the access class. */ | ||
1196 | u16 txop_limit; | ||
1197 | } __attribute__ ((packed)); | ||
1198 | |||
1169 | /************************************************************************* | 1199 | /************************************************************************* |
1170 | 1200 | ||
1171 | Host Interrupt Register (WiLink -> Host) | 1201 | Host Interrupt Register (WiLink -> Host) |
@@ -1322,5 +1352,7 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); | |||
1322 | int wl1251_acx_rate_policies(struct wl1251 *wl); | 1352 | int wl1251_acx_rate_policies(struct wl1251 *wl); |
1323 | int wl1251_acx_mem_cfg(struct wl1251 *wl); | 1353 | int wl1251_acx_mem_cfg(struct wl1251 *wl); |
1324 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); | 1354 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); |
1355 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
1356 | u8 aifs, u16 txop); | ||
1325 | 1357 | ||
1326 | #endif /* __WL1251_ACX_H__ */ | 1358 | #endif /* __WL1251_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 5cb573383ee..5aad56ea715 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c | |||
@@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | |||
294 | goto out; | 294 | goto out; |
295 | } | 295 | } |
296 | 296 | ||
297 | wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); | ||
298 | wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); | ||
299 | wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); | ||
300 | wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); | ||
301 | |||
297 | out: | 302 | out: |
298 | kfree(config); | 303 | kfree(config); |
299 | return ret; | 304 | return ret; |
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.h b/drivers/net/wireless/wl12xx/wl1251_init.h index b3b25ec885e..269cefb3e7d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.h +++ b/drivers/net/wireless/wl12xx/wl1251_init.h | |||
@@ -26,6 +26,53 @@ | |||
26 | 26 | ||
27 | #include "wl1251.h" | 27 | #include "wl1251.h" |
28 | 28 | ||
29 | enum { | ||
30 | /* best effort/legacy */ | ||
31 | AC_BE = 0, | ||
32 | |||
33 | /* background */ | ||
34 | AC_BK = 1, | ||
35 | |||
36 | /* video */ | ||
37 | AC_VI = 2, | ||
38 | |||
39 | /* voice */ | ||
40 | AC_VO = 3, | ||
41 | |||
42 | /* broadcast dummy access category */ | ||
43 | AC_BCAST = 4, | ||
44 | |||
45 | NUM_ACCESS_CATEGORIES = 4 | ||
46 | }; | ||
47 | |||
48 | /* following are defult values for the IE fields*/ | ||
49 | #define CWMIN_BK 15 | ||
50 | #define CWMIN_BE 15 | ||
51 | #define CWMIN_VI 7 | ||
52 | #define CWMIN_VO 3 | ||
53 | #define CWMAX_BK 1023 | ||
54 | #define CWMAX_BE 63 | ||
55 | #define CWMAX_VI 15 | ||
56 | #define CWMAX_VO 7 | ||
57 | |||
58 | /* slot number setting to start transmission at PIFS interval */ | ||
59 | #define AIFS_PIFS 1 | ||
60 | |||
61 | /* | ||
62 | * slot number setting to start transmission at DIFS interval - normal DCF | ||
63 | * access | ||
64 | */ | ||
65 | #define AIFS_DIFS 2 | ||
66 | |||
67 | #define AIFSN_BK 7 | ||
68 | #define AIFSN_BE 3 | ||
69 | #define AIFSN_VI AIFS_PIFS | ||
70 | #define AIFSN_VO AIFS_PIFS | ||
71 | #define TXOP_BK 0 | ||
72 | #define TXOP_BE 0 | ||
73 | #define TXOP_VI 3008 | ||
74 | #define TXOP_VO 1504 | ||
75 | |||
29 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl); | 76 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl); |
30 | int wl1251_hw_init_templates_config(struct wl1251 *wl); | 77 | int wl1251_hw_init_templates_config(struct wl1251 *wl); |
31 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); | 78 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 24050d56a9d..c1c7cb5aea2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -1285,6 +1285,32 @@ static struct ieee80211_channel wl1251_channels[] = { | |||
1285 | { .hw_value = 13, .center_freq = 2472}, | 1285 | { .hw_value = 13, .center_freq = 2472}, |
1286 | }; | 1286 | }; |
1287 | 1287 | ||
1288 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
1289 | const struct ieee80211_tx_queue_params *params) | ||
1290 | { | ||
1291 | struct wl1251 *wl = hw->priv; | ||
1292 | int ret; | ||
1293 | |||
1294 | mutex_lock(&wl->mutex); | ||
1295 | |||
1296 | wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
1297 | |||
1298 | ret = wl1251_ps_elp_wakeup(wl); | ||
1299 | if (ret < 0) | ||
1300 | goto out; | ||
1301 | |||
1302 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), | ||
1303 | params->cw_min, params->cw_max, | ||
1304 | params->aifs, params->txop); | ||
1305 | |||
1306 | wl1251_ps_elp_sleep(wl); | ||
1307 | |||
1308 | out: | ||
1309 | mutex_unlock(&wl->mutex); | ||
1310 | |||
1311 | return ret; | ||
1312 | } | ||
1313 | |||
1288 | /* can't be const, mac80211 writes to this */ | 1314 | /* can't be const, mac80211 writes to this */ |
1289 | static struct ieee80211_supported_band wl1251_band_2ghz = { | 1315 | static struct ieee80211_supported_band wl1251_band_2ghz = { |
1290 | .channels = wl1251_channels, | 1316 | .channels = wl1251_channels, |
@@ -1305,6 +1331,7 @@ static const struct ieee80211_ops wl1251_ops = { | |||
1305 | .hw_scan = wl1251_op_hw_scan, | 1331 | .hw_scan = wl1251_op_hw_scan, |
1306 | .bss_info_changed = wl1251_op_bss_info_changed, | 1332 | .bss_info_changed = wl1251_op_bss_info_changed, |
1307 | .set_rts_threshold = wl1251_op_set_rts_threshold, | 1333 | .set_rts_threshold = wl1251_op_set_rts_threshold, |
1334 | .conf_tx = wl1251_op_conf_tx, | ||
1308 | }; | 1335 | }; |
1309 | 1336 | ||
1310 | static int wl1251_register_hw(struct wl1251 *wl) | 1337 | static int wl1251_register_hw(struct wl1251 *wl) |
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h index 7c1c1665c81..b7bead8b0ae 100644 --- a/drivers/net/wireless/wl12xx/wl1251_tx.h +++ b/drivers/net/wireless/wl12xx/wl1251_tx.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define __WL1251_TX_H__ | 26 | #define __WL1251_TX_H__ |
27 | 27 | ||
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include "wl1251_acx.h" | ||
29 | 30 | ||
30 | /* | 31 | /* |
31 | * | 32 | * |
@@ -209,6 +210,25 @@ struct tx_result { | |||
209 | u8 done_2; | 210 | u8 done_2; |
210 | } __attribute__ ((packed)); | 211 | } __attribute__ ((packed)); |
211 | 212 | ||
213 | static inline int wl1251_tx_get_queue(int queue) | ||
214 | { | ||
215 | /* FIXME: use best effort until WMM is enabled */ | ||
216 | return QOS_AC_BE; | ||
217 | |||
218 | switch (queue) { | ||
219 | case 0: | ||
220 | return QOS_AC_VO; | ||
221 | case 1: | ||
222 | return QOS_AC_VI; | ||
223 | case 2: | ||
224 | return QOS_AC_BE; | ||
225 | case 3: | ||
226 | return QOS_AC_BK; | ||
227 | default: | ||
228 | return QOS_AC_BE; | ||
229 | } | ||
230 | } | ||
231 | |||
212 | void wl1251_tx_work(struct work_struct *work); | 232 | void wl1251_tx_work(struct work_struct *work); |
213 | void wl1251_tx_complete(struct wl1251 *wl); | 233 | void wl1251_tx_complete(struct wl1251 *wl); |
214 | void wl1251_tx_flush(struct wl1251 *wl); | 234 | void wl1251_tx_flush(struct wl1251 *wl); |