diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1251_init.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_init.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index df6c60f0fd66..1c587eceacc4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "wl12xx_80211.h" | 28 | #include "wl12xx_80211.h" |
29 | #include "wl1251_acx.h" | 29 | #include "wl1251_acx.h" |
30 | #include "wl1251_cmd.h" | 30 | #include "wl1251_cmd.h" |
31 | #include "reg.h" | ||
31 | 32 | ||
32 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) | 33 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) |
33 | { | 34 | { |
@@ -198,3 +199,215 @@ int wl1251_hw_init_power_auth(struct wl1251 *wl) | |||
198 | { | 199 | { |
199 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | 200 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); |
200 | } | 201 | } |
202 | |||
203 | int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
204 | { | ||
205 | int ret; | ||
206 | |||
207 | ret = wl1251_acx_mem_cfg(wl); | ||
208 | if (ret < 0) | ||
209 | return ret; | ||
210 | |||
211 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
212 | GFP_KERNEL); | ||
213 | if (!wl->target_mem_map) { | ||
214 | wl1251_error("couldn't allocate target memory map"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | /* we now ask for the firmware built memory map */ | ||
219 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
220 | sizeof(struct wl1251_acx_mem_map)); | ||
221 | if (ret < 0) { | ||
222 | wl1251_error("couldn't retrieve firmware memory map"); | ||
223 | kfree(wl->target_mem_map); | ||
224 | wl->target_mem_map = NULL; | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
232 | struct acx_tx_queue_qos_config *config, | ||
233 | u32 num_blocks) | ||
234 | { | ||
235 | config->qid = qid; | ||
236 | |||
237 | switch (qid) { | ||
238 | case QOS_AC_BE: | ||
239 | config->high_threshold = | ||
240 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
241 | config->low_threshold = | ||
242 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
243 | break; | ||
244 | case QOS_AC_BK: | ||
245 | config->high_threshold = | ||
246 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
247 | config->low_threshold = | ||
248 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
249 | break; | ||
250 | case QOS_AC_VI: | ||
251 | config->high_threshold = | ||
252 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
253 | config->low_threshold = | ||
254 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
255 | break; | ||
256 | case QOS_AC_VO: | ||
257 | config->high_threshold = | ||
258 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
259 | config->low_threshold = | ||
260 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
261 | break; | ||
262 | default: | ||
263 | wl1251_error("Invalid TX queue id: %d", qid); | ||
264 | return -EINVAL; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
271 | { | ||
272 | struct acx_tx_queue_qos_config *config; | ||
273 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
274 | int ret, i; | ||
275 | |||
276 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
277 | |||
278 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
279 | if (!config) { | ||
280 | ret = -ENOMEM; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
285 | ret = wl1251_hw_init_txq_fill(i, config, | ||
286 | wl_mem_map->num_tx_mem_blocks); | ||
287 | if (ret < 0) | ||
288 | goto out; | ||
289 | |||
290 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
291 | config, sizeof(*config)); | ||
292 | if (ret < 0) | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | out: | ||
297 | kfree(config); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
302 | { | ||
303 | int ret; | ||
304 | |||
305 | /* asking for the data path parameters */ | ||
306 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
307 | GFP_KERNEL); | ||
308 | if (!wl->data_path) { | ||
309 | wl1251_error("Couldnt allocate data path parameters"); | ||
310 | return -ENOMEM; | ||
311 | } | ||
312 | |||
313 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
314 | if (ret < 0) { | ||
315 | kfree(wl->data_path); | ||
316 | wl->data_path = NULL; | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | |||
324 | int wl1251_hw_init(struct wl1251 *wl) | ||
325 | { | ||
326 | struct wl1251_acx_mem_map *wl_mem_map; | ||
327 | int ret; | ||
328 | |||
329 | ret = wl1251_hw_init_hwenc_config(wl); | ||
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
333 | /* Template settings */ | ||
334 | ret = wl1251_hw_init_templates_config(wl); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | /* Default memory configuration */ | ||
339 | ret = wl1251_hw_init_mem_config(wl); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | /* Default data path configuration */ | ||
344 | ret = wl1251_hw_init_data_path_config(wl); | ||
345 | if (ret < 0) | ||
346 | goto out_free_memmap; | ||
347 | |||
348 | /* RX config */ | ||
349 | ret = wl1251_hw_init_rx_config(wl, | ||
350 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
351 | RX_FILTER_OPTION_DEF); | ||
352 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
353 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
354 | if (ret < 0) | ||
355 | goto out_free_data_path; | ||
356 | |||
357 | /* TX queues config */ | ||
358 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
359 | if (ret < 0) | ||
360 | goto out_free_data_path; | ||
361 | |||
362 | /* PHY layer config */ | ||
363 | ret = wl1251_hw_init_phy_config(wl); | ||
364 | if (ret < 0) | ||
365 | goto out_free_data_path; | ||
366 | |||
367 | /* Beacon filtering */ | ||
368 | ret = wl1251_hw_init_beacon_filter(wl); | ||
369 | if (ret < 0) | ||
370 | goto out_free_data_path; | ||
371 | |||
372 | /* Bluetooth WLAN coexistence */ | ||
373 | ret = wl1251_hw_init_pta(wl); | ||
374 | if (ret < 0) | ||
375 | goto out_free_data_path; | ||
376 | |||
377 | /* Energy detection */ | ||
378 | ret = wl1251_hw_init_energy_detection(wl); | ||
379 | if (ret < 0) | ||
380 | goto out_free_data_path; | ||
381 | |||
382 | /* Beacons and boradcast settings */ | ||
383 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
384 | if (ret < 0) | ||
385 | goto out_free_data_path; | ||
386 | |||
387 | /* Enable data path */ | ||
388 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
389 | if (ret < 0) | ||
390 | goto out_free_data_path; | ||
391 | |||
392 | /* Default power state */ | ||
393 | ret = wl1251_hw_init_power_auth(wl); | ||
394 | if (ret < 0) | ||
395 | goto out_free_data_path; | ||
396 | |||
397 | wl_mem_map = wl->target_mem_map; | ||
398 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
399 | wl_mem_map->num_tx_mem_blocks, | ||
400 | wl->data_path->tx_control_addr, | ||
401 | wl_mem_map->num_rx_mem_blocks, | ||
402 | wl->data_path->rx_control_addr); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | out_free_data_path: | ||
407 | kfree(wl->data_path); | ||
408 | |||
409 | out_free_memmap: | ||
410 | kfree(wl->target_mem_map); | ||
411 | |||
412 | return ret; | ||
413 | } | ||