init.c revision 6bd650299046f00df6d7374c7f61c5afe6df6696
1/* 2 * This file is part of wl1271 3 * 4 * Copyright (C) 2009 Nokia Corporation 5 * 6 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 */ 23 24#include <linux/kernel.h> 25#include <linux/module.h> 26#include <linux/slab.h> 27 28#include "init.h" 29#include "wl12xx_80211.h" 30#include "acx.h" 31#include "cmd.h" 32#include "reg.h" 33#include "tx.h" 34#include "io.h" 35 36int wl1271_init_templates_config(struct wl1271 *wl) 37{ 38 int ret, i; 39 40 /* send empty templates for fw memory reservation */ 41 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, 42 WL1271_CMD_TEMPL_DFLT_SIZE, 43 0, WL1271_RATE_AUTOMATIC); 44 if (ret < 0) 45 return ret; 46 47 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, 48 NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, 49 WL1271_RATE_AUTOMATIC); 50 if (ret < 0) 51 return ret; 52 53 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, 54 sizeof(struct wl12xx_null_data_template), 55 0, WL1271_RATE_AUTOMATIC); 56 if (ret < 0) 57 return ret; 58 59 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, 60 sizeof(struct wl12xx_ps_poll_template), 61 0, WL1271_RATE_AUTOMATIC); 62 if (ret < 0) 63 return ret; 64 65 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, 66 sizeof 67 (struct wl12xx_qos_null_data_template), 68 0, WL1271_RATE_AUTOMATIC); 69 if (ret < 0) 70 return ret; 71 72 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, 73 WL1271_CMD_TEMPL_DFLT_SIZE, 74 0, WL1271_RATE_AUTOMATIC); 75 if (ret < 0) 76 return ret; 77 78 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, 79 WL1271_CMD_TEMPL_DFLT_SIZE, 80 0, WL1271_RATE_AUTOMATIC); 81 if (ret < 0) 82 return ret; 83 84 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL, 85 sizeof 86 (struct wl12xx_arp_rsp_template), 87 0, WL1271_RATE_AUTOMATIC); 88 if (ret < 0) 89 return ret; 90 91 /* 92 * Put very large empty placeholders for all templates. These 93 * reserve memory for later. 94 */ 95 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, 96 WL1271_CMD_TEMPL_MAX_SIZE, 97 0, WL1271_RATE_AUTOMATIC); 98 if (ret < 0) 99 return ret; 100 101 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, 102 WL1271_CMD_TEMPL_MAX_SIZE, 103 0, WL1271_RATE_AUTOMATIC); 104 if (ret < 0) 105 return ret; 106 107 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, 108 sizeof 109 (struct wl12xx_disconn_template), 110 0, WL1271_RATE_AUTOMATIC); 111 if (ret < 0) 112 return ret; 113 114 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { 115 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, 116 WL1271_CMD_TEMPL_DFLT_SIZE, i, 117 WL1271_RATE_AUTOMATIC); 118 if (ret < 0) 119 return ret; 120 } 121 122 return 0; 123} 124 125static int wl1271_ap_init_deauth_template(struct wl1271 *wl, 126 struct wl12xx_vif *wlvif) 127{ 128 struct wl12xx_disconn_template *tmpl; 129 int ret; 130 u32 rate; 131 132 tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); 133 if (!tmpl) { 134 ret = -ENOMEM; 135 goto out; 136 } 137 138 tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | 139 IEEE80211_STYPE_DEAUTH); 140 141 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); 142 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, 143 tmpl, sizeof(*tmpl), 0, rate); 144 145out: 146 kfree(tmpl); 147 return ret; 148} 149 150static int wl1271_ap_init_null_template(struct wl1271 *wl, 151 struct ieee80211_vif *vif) 152{ 153 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 154 struct ieee80211_hdr_3addr *nullfunc; 155 int ret; 156 u32 rate; 157 158 nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); 159 if (!nullfunc) { 160 ret = -ENOMEM; 161 goto out; 162 } 163 164 nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 165 IEEE80211_STYPE_NULLFUNC | 166 IEEE80211_FCTL_FROMDS); 167 168 /* nullfunc->addr1 is filled by FW */ 169 170 memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); 171 memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); 172 173 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); 174 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, 175 sizeof(*nullfunc), 0, rate); 176 177out: 178 kfree(nullfunc); 179 return ret; 180} 181 182static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, 183 struct ieee80211_vif *vif) 184{ 185 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 186 struct ieee80211_qos_hdr *qosnull; 187 int ret; 188 u32 rate; 189 190 qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); 191 if (!qosnull) { 192 ret = -ENOMEM; 193 goto out; 194 } 195 196 qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 197 IEEE80211_STYPE_QOS_NULLFUNC | 198 IEEE80211_FCTL_FROMDS); 199 200 /* qosnull->addr1 is filled by FW */ 201 202 memcpy(qosnull->addr2, vif->addr, ETH_ALEN); 203 memcpy(qosnull->addr3, vif->addr, ETH_ALEN); 204 205 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); 206 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, 207 sizeof(*qosnull), 0, rate); 208 209out: 210 kfree(qosnull); 211 return ret; 212} 213 214static int wl12xx_init_rx_config(struct wl1271 *wl) 215{ 216 int ret; 217 218 ret = wl1271_acx_rx_msdu_life_time(wl); 219 if (ret < 0) 220 return ret; 221 222 return 0; 223} 224 225int wl1271_init_phy_config(struct wl1271 *wl) 226{ 227 int ret; 228 229 ret = wl1271_acx_pd_threshold(wl); 230 if (ret < 0) 231 return ret; 232 233 return 0; 234} 235 236static int wl12xx_init_phy_vif_config(struct wl1271 *wl, 237 struct wl12xx_vif *wlvif) 238{ 239 int ret; 240 241 ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME); 242 if (ret < 0) 243 return ret; 244 245 ret = wl1271_acx_service_period_timeout(wl, wlvif); 246 if (ret < 0) 247 return ret; 248 249 ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold); 250 if (ret < 0) 251 return ret; 252 253 return 0; 254} 255 256static int wl1271_init_beacon_filter(struct wl1271 *wl, 257 struct wl12xx_vif *wlvif) 258{ 259 int ret; 260 261 /* disable beacon filtering at this stage */ 262 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); 263 if (ret < 0) 264 return ret; 265 266 ret = wl1271_acx_beacon_filter_table(wl, wlvif); 267 if (ret < 0) 268 return ret; 269 270 return 0; 271} 272 273int wl1271_init_pta(struct wl1271 *wl) 274{ 275 int ret; 276 277 ret = wl12xx_acx_sg_cfg(wl); 278 if (ret < 0) 279 return ret; 280 281 ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); 282 if (ret < 0) 283 return ret; 284 285 return 0; 286} 287 288int wl1271_init_energy_detection(struct wl1271 *wl) 289{ 290 int ret; 291 292 ret = wl1271_acx_cca_threshold(wl); 293 if (ret < 0) 294 return ret; 295 296 return 0; 297} 298 299static int wl1271_init_beacon_broadcast(struct wl1271 *wl, 300 struct wl12xx_vif *wlvif) 301{ 302 int ret; 303 304 ret = wl1271_acx_bcn_dtim_options(wl, wlvif); 305 if (ret < 0) 306 return ret; 307 308 return 0; 309} 310 311static int wl12xx_init_fwlog(struct wl1271 *wl) 312{ 313 int ret; 314 315 if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) 316 return 0; 317 318 ret = wl12xx_cmd_config_fwlog(wl); 319 if (ret < 0) 320 return ret; 321 322 return 0; 323} 324 325/* generic sta initialization (non vif-specific) */ 326static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) 327{ 328 int ret; 329 330 if (wl->chip.id != CHIP_ID_1283_PG20) { 331 ret = wl1271_cmd_ext_radio_parms(wl); 332 if (ret < 0) 333 return ret; 334 } 335 336 /* PS config */ 337 ret = wl12xx_acx_config_ps(wl, wlvif); 338 if (ret < 0) 339 return ret; 340 341 /* FM WLAN coexistence */ 342 ret = wl1271_acx_fm_coex(wl); 343 if (ret < 0) 344 return ret; 345 346 ret = wl1271_acx_sta_rate_policies(wl, wlvif); 347 if (ret < 0) 348 return ret; 349 350 return 0; 351} 352 353static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, 354 struct ieee80211_vif *vif) 355{ 356 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 357 int ret, i; 358 359 /* disable all keep-alive templates */ 360 for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { 361 ret = wl1271_acx_keep_alive_config(wl, wlvif, i, 362 ACX_KEEP_ALIVE_TPL_INVALID); 363 if (ret < 0) 364 return ret; 365 } 366 367 /* disable the keep-alive feature */ 368 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); 369 if (ret < 0) 370 return ret; 371 372 return 0; 373} 374 375/* generic ap initialization (non vif-specific) */ 376static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) 377{ 378 int ret; 379 380 ret = wl1271_init_ap_rates(wl, wlvif); 381 if (ret < 0) 382 return ret; 383 384 return 0; 385} 386 387int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) 388{ 389 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 390 int ret; 391 392 ret = wl1271_ap_init_deauth_template(wl, wlvif); 393 if (ret < 0) 394 return ret; 395 396 ret = wl1271_ap_init_null_template(wl, vif); 397 if (ret < 0) 398 return ret; 399 400 ret = wl1271_ap_init_qos_null_template(wl, vif); 401 if (ret < 0) 402 return ret; 403 404 /* 405 * when operating as AP we want to receive external beacons for 406 * configuring ERP protection. 407 */ 408 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); 409 if (ret < 0) 410 return ret; 411 412 return 0; 413} 414 415static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl, 416 struct ieee80211_vif *vif) 417{ 418 return wl1271_ap_init_templates(wl, vif); 419} 420 421int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) 422{ 423 int i, ret; 424 struct conf_tx_rate_class rc; 425 u32 supported_rates; 426 427 wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", 428 wlvif->basic_rate_set); 429 430 if (wlvif->basic_rate_set == 0) 431 return -EINVAL; 432 433 rc.enabled_rates = wlvif->basic_rate_set; 434 rc.long_retry_limit = 10; 435 rc.short_retry_limit = 10; 436 rc.aflags = 0; 437 ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE); 438 if (ret < 0) 439 return ret; 440 441 /* use the min basic rate for AP broadcast/multicast */ 442 rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); 443 rc.short_retry_limit = 10; 444 rc.long_retry_limit = 10; 445 rc.aflags = 0; 446 ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE); 447 if (ret < 0) 448 return ret; 449 450 /* 451 * If the basic rates contain OFDM rates, use OFDM only 452 * rates for unicast TX as well. Else use all supported rates. 453 */ 454 if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) 455 supported_rates = CONF_TX_OFDM_RATES; 456 else 457 supported_rates = CONF_TX_AP_ENABLED_RATES; 458 459 /* unconditionally enable HT rates */ 460 supported_rates |= CONF_TX_MCS_RATES; 461 462 /* configure unicast TX rate classes */ 463 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { 464 rc.enabled_rates = supported_rates; 465 rc.short_retry_limit = 10; 466 rc.long_retry_limit = 10; 467 rc.aflags = 0; 468 ret = wl1271_acx_ap_rate_policy(wl, &rc, i); 469 if (ret < 0) 470 return ret; 471 } 472 473 return 0; 474} 475 476static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) 477{ 478 /* Reset the BA RX indicators */ 479 wlvif->ba_allowed = true; 480 wl->ba_rx_session_count = 0; 481 482 /* BA is supported in STA/AP modes */ 483 if (wlvif->bss_type != BSS_TYPE_AP_BSS && 484 wlvif->bss_type != BSS_TYPE_STA_BSS) { 485 wlvif->ba_support = false; 486 return 0; 487 } 488 489 wlvif->ba_support = true; 490 491 /* 802.11n initiator BA session setting */ 492 return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); 493} 494 495int wl1271_chip_specific_init(struct wl1271 *wl) 496{ 497 int ret = 0; 498 499 if (wl->chip.id == CHIP_ID_1283_PG20) { 500 u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; 501 502 if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) 503 /* Enable SDIO padding */ 504 host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; 505 506 /* Must be before wl1271_acx_init_mem_config() */ 507 ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); 508 if (ret < 0) 509 goto out; 510 } 511out: 512 return ret; 513} 514 515/* vif-specifc initialization */ 516static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) 517{ 518 int ret; 519 520 ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0); 521 if (ret < 0) 522 return ret; 523 524 /* Initialize connection monitoring thresholds */ 525 ret = wl1271_acx_conn_monit_params(wl, wlvif, false); 526 if (ret < 0) 527 return ret; 528 529 /* Beacon filtering */ 530 ret = wl1271_init_beacon_filter(wl, wlvif); 531 if (ret < 0) 532 return ret; 533 534 /* Beacons and broadcast settings */ 535 ret = wl1271_init_beacon_broadcast(wl, wlvif); 536 if (ret < 0) 537 return ret; 538 539 /* Configure rssi/snr averaging weights */ 540 ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif); 541 if (ret < 0) 542 return ret; 543 544 return 0; 545} 546 547/* vif-specific intialization */ 548static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) 549{ 550 int ret; 551 552 ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); 553 if (ret < 0) 554 return ret; 555 556 /* initialize Tx power */ 557 ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level); 558 if (ret < 0) 559 return ret; 560 561 return 0; 562} 563 564int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) 565{ 566 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 567 struct conf_tx_ac_category *conf_ac; 568 struct conf_tx_tid *conf_tid; 569 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); 570 int ret, i; 571 572 /* 573 * consider all existing roles before configuring psm. 574 * TODO: reconfigure on interface removal. 575 */ 576 if (!wl->ap_count) { 577 if (is_ap) { 578 /* Configure for power always on */ 579 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); 580 if (ret < 0) 581 return ret; 582 } else if (!wl->sta_count) { 583 /* Configure for ELP power saving */ 584 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); 585 if (ret < 0) 586 return ret; 587 } 588 } 589 590 /* Mode specific init */ 591 if (is_ap) { 592 ret = wl1271_ap_hw_init(wl, wlvif); 593 if (ret < 0) 594 return ret; 595 596 ret = wl12xx_init_ap_role(wl, wlvif); 597 if (ret < 0) 598 return ret; 599 } else { 600 ret = wl1271_sta_hw_init(wl, wlvif); 601 if (ret < 0) 602 return ret; 603 604 ret = wl12xx_init_sta_role(wl, wlvif); 605 if (ret < 0) 606 return ret; 607 } 608 609 wl12xx_init_phy_vif_config(wl, wlvif); 610 611 /* Default TID/AC configuration */ 612 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); 613 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { 614 conf_ac = &wl->conf.tx.ac_conf[i]; 615 ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, 616 conf_ac->cw_min, conf_ac->cw_max, 617 conf_ac->aifsn, conf_ac->tx_op_limit); 618 if (ret < 0) 619 return ret; 620 621 conf_tid = &wl->conf.tx.tid_conf[i]; 622 ret = wl1271_acx_tid_cfg(wl, wlvif, 623 conf_tid->queue_id, 624 conf_tid->channel_type, 625 conf_tid->tsid, 626 conf_tid->ps_scheme, 627 conf_tid->ack_policy, 628 conf_tid->apsd_conf[0], 629 conf_tid->apsd_conf[1]); 630 if (ret < 0) 631 return ret; 632 } 633 634 /* Configure HW encryption */ 635 ret = wl1271_acx_feature_cfg(wl, wlvif); 636 if (ret < 0) 637 return ret; 638 639 /* Mode specific init - post mem init */ 640 if (is_ap) 641 ret = wl1271_ap_hw_init_post_mem(wl, vif); 642 else 643 ret = wl1271_sta_hw_init_post_mem(wl, vif); 644 645 if (ret < 0) 646 return ret; 647 648 /* Configure initiator BA sessions policies */ 649 ret = wl1271_set_ba_policies(wl, wlvif); 650 if (ret < 0) 651 return ret; 652 653 return 0; 654} 655 656int wl1271_hw_init(struct wl1271 *wl) 657{ 658 int ret; 659 660 if (wl->chip.id == CHIP_ID_1283_PG20) 661 ret = wl128x_cmd_general_parms(wl); 662 else 663 ret = wl1271_cmd_general_parms(wl); 664 if (ret < 0) 665 return ret; 666 667 if (wl->chip.id == CHIP_ID_1283_PG20) 668 ret = wl128x_cmd_radio_parms(wl); 669 else 670 ret = wl1271_cmd_radio_parms(wl); 671 if (ret < 0) 672 return ret; 673 674 /* Chip-specific init */ 675 ret = wl1271_chip_specific_init(wl); 676 if (ret < 0) 677 return ret; 678 679 /* Init templates */ 680 ret = wl1271_init_templates_config(wl); 681 if (ret < 0) 682 return ret; 683 684 ret = wl12xx_acx_mem_cfg(wl); 685 if (ret < 0) 686 return ret; 687 688 /* Configure the FW logger */ 689 ret = wl12xx_init_fwlog(wl); 690 if (ret < 0) 691 return ret; 692 693 /* Bluetooth WLAN coexistence */ 694 ret = wl1271_init_pta(wl); 695 if (ret < 0) 696 return ret; 697 698 /* Default memory configuration */ 699 ret = wl1271_acx_init_mem_config(wl); 700 if (ret < 0) 701 return ret; 702 703 /* RX config */ 704 ret = wl12xx_init_rx_config(wl); 705 if (ret < 0) 706 goto out_free_memmap; 707 708 /* PHY layer config */ 709 ret = wl1271_init_phy_config(wl); 710 if (ret < 0) 711 goto out_free_memmap; 712 713 ret = wl1271_acx_dco_itrim_params(wl); 714 if (ret < 0) 715 goto out_free_memmap; 716 717 /* Configure TX patch complete interrupt behavior */ 718 ret = wl1271_acx_tx_config_options(wl); 719 if (ret < 0) 720 goto out_free_memmap; 721 722 /* RX complete interrupt pacing */ 723 ret = wl1271_acx_init_rx_interrupt(wl); 724 if (ret < 0) 725 goto out_free_memmap; 726 727 /* Energy detection */ 728 ret = wl1271_init_energy_detection(wl); 729 if (ret < 0) 730 goto out_free_memmap; 731 732 /* Default fragmentation threshold */ 733 ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); 734 if (ret < 0) 735 goto out_free_memmap; 736 737 /* Enable data path */ 738 ret = wl1271_cmd_data_path(wl, 1); 739 if (ret < 0) 740 goto out_free_memmap; 741 742 /* configure PM */ 743 ret = wl1271_acx_pm_config(wl); 744 if (ret < 0) 745 goto out_free_memmap; 746 747 ret = wl12xx_acx_set_rate_mgmt_params(wl); 748 if (ret < 0) 749 goto out_free_memmap; 750 751 /* configure hangover */ 752 ret = wl12xx_acx_config_hangover(wl); 753 if (ret < 0) 754 goto out_free_memmap; 755 756 return 0; 757 758 out_free_memmap: 759 kfree(wl->target_mem_map); 760 wl->target_mem_map = NULL; 761 762 return ret; 763} 764