1*90921014SLuciano Coelho #include "acx.h" 2*90921014SLuciano Coelho 3*90921014SLuciano Coelho #include <linux/module.h> 4*90921014SLuciano Coelho #include <linux/slab.h> 5*90921014SLuciano Coelho #include <linux/crc7.h> 6*90921014SLuciano Coelho 7*90921014SLuciano Coelho #include "wl1251.h" 8*90921014SLuciano Coelho #include "reg.h" 9*90921014SLuciano Coelho #include "cmd.h" 10*90921014SLuciano Coelho #include "ps.h" 11*90921014SLuciano Coelho 12*90921014SLuciano Coelho int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, 13*90921014SLuciano Coelho u8 mgt_rate, u8 mgt_mod) 14*90921014SLuciano Coelho { 15*90921014SLuciano Coelho struct acx_fw_gen_frame_rates *rates; 16*90921014SLuciano Coelho int ret; 17*90921014SLuciano Coelho 18*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx frame rates"); 19*90921014SLuciano Coelho 20*90921014SLuciano Coelho rates = kzalloc(sizeof(*rates), GFP_KERNEL); 21*90921014SLuciano Coelho if (!rates) { 22*90921014SLuciano Coelho ret = -ENOMEM; 23*90921014SLuciano Coelho goto out; 24*90921014SLuciano Coelho } 25*90921014SLuciano Coelho 26*90921014SLuciano Coelho rates->tx_ctrl_frame_rate = ctrl_rate; 27*90921014SLuciano Coelho rates->tx_ctrl_frame_mod = ctrl_mod; 28*90921014SLuciano Coelho rates->tx_mgt_frame_rate = mgt_rate; 29*90921014SLuciano Coelho rates->tx_mgt_frame_mod = mgt_mod; 30*90921014SLuciano Coelho 31*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, 32*90921014SLuciano Coelho rates, sizeof(*rates)); 33*90921014SLuciano Coelho if (ret < 0) { 34*90921014SLuciano Coelho wl1251_error("Failed to set FW rates and modulation"); 35*90921014SLuciano Coelho goto out; 36*90921014SLuciano Coelho } 37*90921014SLuciano Coelho 38*90921014SLuciano Coelho out: 39*90921014SLuciano Coelho kfree(rates); 40*90921014SLuciano Coelho return ret; 41*90921014SLuciano Coelho } 42*90921014SLuciano Coelho 43*90921014SLuciano Coelho 44*90921014SLuciano Coelho int wl1251_acx_station_id(struct wl1251 *wl) 45*90921014SLuciano Coelho { 46*90921014SLuciano Coelho struct acx_dot11_station_id *mac; 47*90921014SLuciano Coelho int ret, i; 48*90921014SLuciano Coelho 49*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); 50*90921014SLuciano Coelho 51*90921014SLuciano Coelho mac = kzalloc(sizeof(*mac), GFP_KERNEL); 52*90921014SLuciano Coelho if (!mac) { 53*90921014SLuciano Coelho ret = -ENOMEM; 54*90921014SLuciano Coelho goto out; 55*90921014SLuciano Coelho } 56*90921014SLuciano Coelho 57*90921014SLuciano Coelho for (i = 0; i < ETH_ALEN; i++) 58*90921014SLuciano Coelho mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; 59*90921014SLuciano Coelho 60*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); 61*90921014SLuciano Coelho if (ret < 0) 62*90921014SLuciano Coelho goto out; 63*90921014SLuciano Coelho 64*90921014SLuciano Coelho out: 65*90921014SLuciano Coelho kfree(mac); 66*90921014SLuciano Coelho return ret; 67*90921014SLuciano Coelho } 68*90921014SLuciano Coelho 69*90921014SLuciano Coelho int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) 70*90921014SLuciano Coelho { 71*90921014SLuciano Coelho struct acx_dot11_default_key *default_key; 72*90921014SLuciano Coelho int ret; 73*90921014SLuciano Coelho 74*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); 75*90921014SLuciano Coelho 76*90921014SLuciano Coelho default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); 77*90921014SLuciano Coelho if (!default_key) { 78*90921014SLuciano Coelho ret = -ENOMEM; 79*90921014SLuciano Coelho goto out; 80*90921014SLuciano Coelho } 81*90921014SLuciano Coelho 82*90921014SLuciano Coelho default_key->id = key_id; 83*90921014SLuciano Coelho 84*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, 85*90921014SLuciano Coelho default_key, sizeof(*default_key)); 86*90921014SLuciano Coelho if (ret < 0) { 87*90921014SLuciano Coelho wl1251_error("Couldn't set default key"); 88*90921014SLuciano Coelho goto out; 89*90921014SLuciano Coelho } 90*90921014SLuciano Coelho 91*90921014SLuciano Coelho wl->default_key = key_id; 92*90921014SLuciano Coelho 93*90921014SLuciano Coelho out: 94*90921014SLuciano Coelho kfree(default_key); 95*90921014SLuciano Coelho return ret; 96*90921014SLuciano Coelho } 97*90921014SLuciano Coelho 98*90921014SLuciano Coelho int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, 99*90921014SLuciano Coelho u8 listen_interval) 100*90921014SLuciano Coelho { 101*90921014SLuciano Coelho struct acx_wake_up_condition *wake_up; 102*90921014SLuciano Coelho int ret; 103*90921014SLuciano Coelho 104*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx wake up conditions"); 105*90921014SLuciano Coelho 106*90921014SLuciano Coelho wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); 107*90921014SLuciano Coelho if (!wake_up) { 108*90921014SLuciano Coelho ret = -ENOMEM; 109*90921014SLuciano Coelho goto out; 110*90921014SLuciano Coelho } 111*90921014SLuciano Coelho 112*90921014SLuciano Coelho wake_up->wake_up_event = wake_up_event; 113*90921014SLuciano Coelho wake_up->listen_interval = listen_interval; 114*90921014SLuciano Coelho 115*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, 116*90921014SLuciano Coelho wake_up, sizeof(*wake_up)); 117*90921014SLuciano Coelho if (ret < 0) { 118*90921014SLuciano Coelho wl1251_warning("could not set wake up conditions: %d", ret); 119*90921014SLuciano Coelho goto out; 120*90921014SLuciano Coelho } 121*90921014SLuciano Coelho 122*90921014SLuciano Coelho out: 123*90921014SLuciano Coelho kfree(wake_up); 124*90921014SLuciano Coelho return ret; 125*90921014SLuciano Coelho } 126*90921014SLuciano Coelho 127*90921014SLuciano Coelho int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) 128*90921014SLuciano Coelho { 129*90921014SLuciano Coelho struct acx_sleep_auth *auth; 130*90921014SLuciano Coelho int ret; 131*90921014SLuciano Coelho 132*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx sleep auth"); 133*90921014SLuciano Coelho 134*90921014SLuciano Coelho auth = kzalloc(sizeof(*auth), GFP_KERNEL); 135*90921014SLuciano Coelho if (!auth) { 136*90921014SLuciano Coelho ret = -ENOMEM; 137*90921014SLuciano Coelho goto out; 138*90921014SLuciano Coelho } 139*90921014SLuciano Coelho 140*90921014SLuciano Coelho auth->sleep_auth = sleep_auth; 141*90921014SLuciano Coelho 142*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); 143*90921014SLuciano Coelho 144*90921014SLuciano Coelho out: 145*90921014SLuciano Coelho kfree(auth); 146*90921014SLuciano Coelho return ret; 147*90921014SLuciano Coelho } 148*90921014SLuciano Coelho 149*90921014SLuciano Coelho int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) 150*90921014SLuciano Coelho { 151*90921014SLuciano Coelho struct acx_revision *rev; 152*90921014SLuciano Coelho int ret; 153*90921014SLuciano Coelho 154*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx fw rev"); 155*90921014SLuciano Coelho 156*90921014SLuciano Coelho rev = kzalloc(sizeof(*rev), GFP_KERNEL); 157*90921014SLuciano Coelho if (!rev) { 158*90921014SLuciano Coelho ret = -ENOMEM; 159*90921014SLuciano Coelho goto out; 160*90921014SLuciano Coelho } 161*90921014SLuciano Coelho 162*90921014SLuciano Coelho ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); 163*90921014SLuciano Coelho if (ret < 0) { 164*90921014SLuciano Coelho wl1251_warning("ACX_FW_REV interrogate failed"); 165*90921014SLuciano Coelho goto out; 166*90921014SLuciano Coelho } 167*90921014SLuciano Coelho 168*90921014SLuciano Coelho /* be careful with the buffer sizes */ 169*90921014SLuciano Coelho strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); 170*90921014SLuciano Coelho 171*90921014SLuciano Coelho /* 172*90921014SLuciano Coelho * if the firmware version string is exactly 173*90921014SLuciano Coelho * sizeof(rev->fw_version) long or fw_len is less than 174*90921014SLuciano Coelho * sizeof(rev->fw_version) it won't be null terminated 175*90921014SLuciano Coelho */ 176*90921014SLuciano Coelho buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; 177*90921014SLuciano Coelho 178*90921014SLuciano Coelho out: 179*90921014SLuciano Coelho kfree(rev); 180*90921014SLuciano Coelho return ret; 181*90921014SLuciano Coelho } 182*90921014SLuciano Coelho 183*90921014SLuciano Coelho int wl1251_acx_tx_power(struct wl1251 *wl, int power) 184*90921014SLuciano Coelho { 185*90921014SLuciano Coelho struct acx_current_tx_power *acx; 186*90921014SLuciano Coelho int ret; 187*90921014SLuciano Coelho 188*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); 189*90921014SLuciano Coelho 190*90921014SLuciano Coelho if (power < 0 || power > 25) 191*90921014SLuciano Coelho return -EINVAL; 192*90921014SLuciano Coelho 193*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 194*90921014SLuciano Coelho if (!acx) { 195*90921014SLuciano Coelho ret = -ENOMEM; 196*90921014SLuciano Coelho goto out; 197*90921014SLuciano Coelho } 198*90921014SLuciano Coelho 199*90921014SLuciano Coelho acx->current_tx_power = power * 10; 200*90921014SLuciano Coelho 201*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); 202*90921014SLuciano Coelho if (ret < 0) { 203*90921014SLuciano Coelho wl1251_warning("configure of tx power failed: %d", ret); 204*90921014SLuciano Coelho goto out; 205*90921014SLuciano Coelho } 206*90921014SLuciano Coelho 207*90921014SLuciano Coelho out: 208*90921014SLuciano Coelho kfree(acx); 209*90921014SLuciano Coelho return ret; 210*90921014SLuciano Coelho } 211*90921014SLuciano Coelho 212*90921014SLuciano Coelho int wl1251_acx_feature_cfg(struct wl1251 *wl) 213*90921014SLuciano Coelho { 214*90921014SLuciano Coelho struct acx_feature_config *feature; 215*90921014SLuciano Coelho int ret; 216*90921014SLuciano Coelho 217*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx feature cfg"); 218*90921014SLuciano Coelho 219*90921014SLuciano Coelho feature = kzalloc(sizeof(*feature), GFP_KERNEL); 220*90921014SLuciano Coelho if (!feature) { 221*90921014SLuciano Coelho ret = -ENOMEM; 222*90921014SLuciano Coelho goto out; 223*90921014SLuciano Coelho } 224*90921014SLuciano Coelho 225*90921014SLuciano Coelho /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ 226*90921014SLuciano Coelho feature->data_flow_options = 0; 227*90921014SLuciano Coelho feature->options = 0; 228*90921014SLuciano Coelho 229*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, 230*90921014SLuciano Coelho feature, sizeof(*feature)); 231*90921014SLuciano Coelho if (ret < 0) { 232*90921014SLuciano Coelho wl1251_error("Couldn't set HW encryption"); 233*90921014SLuciano Coelho goto out; 234*90921014SLuciano Coelho } 235*90921014SLuciano Coelho 236*90921014SLuciano Coelho out: 237*90921014SLuciano Coelho kfree(feature); 238*90921014SLuciano Coelho return ret; 239*90921014SLuciano Coelho } 240*90921014SLuciano Coelho 241*90921014SLuciano Coelho int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, 242*90921014SLuciano Coelho size_t len) 243*90921014SLuciano Coelho { 244*90921014SLuciano Coelho int ret; 245*90921014SLuciano Coelho 246*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx mem map"); 247*90921014SLuciano Coelho 248*90921014SLuciano Coelho ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); 249*90921014SLuciano Coelho if (ret < 0) 250*90921014SLuciano Coelho return ret; 251*90921014SLuciano Coelho 252*90921014SLuciano Coelho return 0; 253*90921014SLuciano Coelho } 254*90921014SLuciano Coelho 255*90921014SLuciano Coelho int wl1251_acx_data_path_params(struct wl1251 *wl, 256*90921014SLuciano Coelho struct acx_data_path_params_resp *resp) 257*90921014SLuciano Coelho { 258*90921014SLuciano Coelho struct acx_data_path_params *params; 259*90921014SLuciano Coelho int ret; 260*90921014SLuciano Coelho 261*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx data path params"); 262*90921014SLuciano Coelho 263*90921014SLuciano Coelho params = kzalloc(sizeof(*params), GFP_KERNEL); 264*90921014SLuciano Coelho if (!params) { 265*90921014SLuciano Coelho ret = -ENOMEM; 266*90921014SLuciano Coelho goto out; 267*90921014SLuciano Coelho } 268*90921014SLuciano Coelho 269*90921014SLuciano Coelho params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; 270*90921014SLuciano Coelho params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; 271*90921014SLuciano Coelho 272*90921014SLuciano Coelho params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; 273*90921014SLuciano Coelho params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; 274*90921014SLuciano Coelho 275*90921014SLuciano Coelho params->tx_complete_threshold = 1; 276*90921014SLuciano Coelho 277*90921014SLuciano Coelho params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; 278*90921014SLuciano Coelho 279*90921014SLuciano Coelho params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; 280*90921014SLuciano Coelho 281*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, 282*90921014SLuciano Coelho params, sizeof(*params)); 283*90921014SLuciano Coelho if (ret < 0) 284*90921014SLuciano Coelho goto out; 285*90921014SLuciano Coelho 286*90921014SLuciano Coelho /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ 287*90921014SLuciano Coelho ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, 288*90921014SLuciano Coelho resp, sizeof(*resp)); 289*90921014SLuciano Coelho 290*90921014SLuciano Coelho if (ret < 0) { 291*90921014SLuciano Coelho wl1251_warning("failed to read data path parameters: %d", ret); 292*90921014SLuciano Coelho goto out; 293*90921014SLuciano Coelho } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { 294*90921014SLuciano Coelho wl1251_warning("data path parameter acx status failed"); 295*90921014SLuciano Coelho ret = -EIO; 296*90921014SLuciano Coelho goto out; 297*90921014SLuciano Coelho } 298*90921014SLuciano Coelho 299*90921014SLuciano Coelho out: 300*90921014SLuciano Coelho kfree(params); 301*90921014SLuciano Coelho return ret; 302*90921014SLuciano Coelho } 303*90921014SLuciano Coelho 304*90921014SLuciano Coelho int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) 305*90921014SLuciano Coelho { 306*90921014SLuciano Coelho struct acx_rx_msdu_lifetime *acx; 307*90921014SLuciano Coelho int ret; 308*90921014SLuciano Coelho 309*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); 310*90921014SLuciano Coelho 311*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 312*90921014SLuciano Coelho if (!acx) { 313*90921014SLuciano Coelho ret = -ENOMEM; 314*90921014SLuciano Coelho goto out; 315*90921014SLuciano Coelho } 316*90921014SLuciano Coelho 317*90921014SLuciano Coelho acx->lifetime = life_time; 318*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, 319*90921014SLuciano Coelho acx, sizeof(*acx)); 320*90921014SLuciano Coelho if (ret < 0) { 321*90921014SLuciano Coelho wl1251_warning("failed to set rx msdu life time: %d", ret); 322*90921014SLuciano Coelho goto out; 323*90921014SLuciano Coelho } 324*90921014SLuciano Coelho 325*90921014SLuciano Coelho out: 326*90921014SLuciano Coelho kfree(acx); 327*90921014SLuciano Coelho return ret; 328*90921014SLuciano Coelho } 329*90921014SLuciano Coelho 330*90921014SLuciano Coelho int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) 331*90921014SLuciano Coelho { 332*90921014SLuciano Coelho struct acx_rx_config *rx_config; 333*90921014SLuciano Coelho int ret; 334*90921014SLuciano Coelho 335*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx rx config"); 336*90921014SLuciano Coelho 337*90921014SLuciano Coelho rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); 338*90921014SLuciano Coelho if (!rx_config) { 339*90921014SLuciano Coelho ret = -ENOMEM; 340*90921014SLuciano Coelho goto out; 341*90921014SLuciano Coelho } 342*90921014SLuciano Coelho 343*90921014SLuciano Coelho rx_config->config_options = config; 344*90921014SLuciano Coelho rx_config->filter_options = filter; 345*90921014SLuciano Coelho 346*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_RX_CFG, 347*90921014SLuciano Coelho rx_config, sizeof(*rx_config)); 348*90921014SLuciano Coelho if (ret < 0) { 349*90921014SLuciano Coelho wl1251_warning("failed to set rx config: %d", ret); 350*90921014SLuciano Coelho goto out; 351*90921014SLuciano Coelho } 352*90921014SLuciano Coelho 353*90921014SLuciano Coelho out: 354*90921014SLuciano Coelho kfree(rx_config); 355*90921014SLuciano Coelho return ret; 356*90921014SLuciano Coelho } 357*90921014SLuciano Coelho 358*90921014SLuciano Coelho int wl1251_acx_pd_threshold(struct wl1251 *wl) 359*90921014SLuciano Coelho { 360*90921014SLuciano Coelho struct acx_packet_detection *pd; 361*90921014SLuciano Coelho int ret; 362*90921014SLuciano Coelho 363*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx data pd threshold"); 364*90921014SLuciano Coelho 365*90921014SLuciano Coelho pd = kzalloc(sizeof(*pd), GFP_KERNEL); 366*90921014SLuciano Coelho if (!pd) { 367*90921014SLuciano Coelho ret = -ENOMEM; 368*90921014SLuciano Coelho goto out; 369*90921014SLuciano Coelho } 370*90921014SLuciano Coelho 371*90921014SLuciano Coelho /* FIXME: threshold value not set */ 372*90921014SLuciano Coelho 373*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); 374*90921014SLuciano Coelho if (ret < 0) { 375*90921014SLuciano Coelho wl1251_warning("failed to set pd threshold: %d", ret); 376*90921014SLuciano Coelho goto out; 377*90921014SLuciano Coelho } 378*90921014SLuciano Coelho 379*90921014SLuciano Coelho out: 380*90921014SLuciano Coelho kfree(pd); 381*90921014SLuciano Coelho return ret; 382*90921014SLuciano Coelho } 383*90921014SLuciano Coelho 384*90921014SLuciano Coelho int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) 385*90921014SLuciano Coelho { 386*90921014SLuciano Coelho struct acx_slot *slot; 387*90921014SLuciano Coelho int ret; 388*90921014SLuciano Coelho 389*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx slot"); 390*90921014SLuciano Coelho 391*90921014SLuciano Coelho slot = kzalloc(sizeof(*slot), GFP_KERNEL); 392*90921014SLuciano Coelho if (!slot) { 393*90921014SLuciano Coelho ret = -ENOMEM; 394*90921014SLuciano Coelho goto out; 395*90921014SLuciano Coelho } 396*90921014SLuciano Coelho 397*90921014SLuciano Coelho slot->wone_index = STATION_WONE_INDEX; 398*90921014SLuciano Coelho slot->slot_time = slot_time; 399*90921014SLuciano Coelho 400*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); 401*90921014SLuciano Coelho if (ret < 0) { 402*90921014SLuciano Coelho wl1251_warning("failed to set slot time: %d", ret); 403*90921014SLuciano Coelho goto out; 404*90921014SLuciano Coelho } 405*90921014SLuciano Coelho 406*90921014SLuciano Coelho out: 407*90921014SLuciano Coelho kfree(slot); 408*90921014SLuciano Coelho return ret; 409*90921014SLuciano Coelho } 410*90921014SLuciano Coelho 411*90921014SLuciano Coelho int wl1251_acx_group_address_tbl(struct wl1251 *wl) 412*90921014SLuciano Coelho { 413*90921014SLuciano Coelho struct acx_dot11_grp_addr_tbl *acx; 414*90921014SLuciano Coelho int ret; 415*90921014SLuciano Coelho 416*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx group address tbl"); 417*90921014SLuciano Coelho 418*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 419*90921014SLuciano Coelho if (!acx) { 420*90921014SLuciano Coelho ret = -ENOMEM; 421*90921014SLuciano Coelho goto out; 422*90921014SLuciano Coelho } 423*90921014SLuciano Coelho 424*90921014SLuciano Coelho /* MAC filtering */ 425*90921014SLuciano Coelho acx->enabled = 0; 426*90921014SLuciano Coelho acx->num_groups = 0; 427*90921014SLuciano Coelho memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); 428*90921014SLuciano Coelho 429*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, 430*90921014SLuciano Coelho acx, sizeof(*acx)); 431*90921014SLuciano Coelho if (ret < 0) { 432*90921014SLuciano Coelho wl1251_warning("failed to set group addr table: %d", ret); 433*90921014SLuciano Coelho goto out; 434*90921014SLuciano Coelho } 435*90921014SLuciano Coelho 436*90921014SLuciano Coelho out: 437*90921014SLuciano Coelho kfree(acx); 438*90921014SLuciano Coelho return ret; 439*90921014SLuciano Coelho } 440*90921014SLuciano Coelho 441*90921014SLuciano Coelho int wl1251_acx_service_period_timeout(struct wl1251 *wl) 442*90921014SLuciano Coelho { 443*90921014SLuciano Coelho struct acx_rx_timeout *rx_timeout; 444*90921014SLuciano Coelho int ret; 445*90921014SLuciano Coelho 446*90921014SLuciano Coelho rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); 447*90921014SLuciano Coelho if (!rx_timeout) { 448*90921014SLuciano Coelho ret = -ENOMEM; 449*90921014SLuciano Coelho goto out; 450*90921014SLuciano Coelho } 451*90921014SLuciano Coelho 452*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx service period timeout"); 453*90921014SLuciano Coelho 454*90921014SLuciano Coelho rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; 455*90921014SLuciano Coelho rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; 456*90921014SLuciano Coelho 457*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, 458*90921014SLuciano Coelho rx_timeout, sizeof(*rx_timeout)); 459*90921014SLuciano Coelho if (ret < 0) { 460*90921014SLuciano Coelho wl1251_warning("failed to set service period timeout: %d", 461*90921014SLuciano Coelho ret); 462*90921014SLuciano Coelho goto out; 463*90921014SLuciano Coelho } 464*90921014SLuciano Coelho 465*90921014SLuciano Coelho out: 466*90921014SLuciano Coelho kfree(rx_timeout); 467*90921014SLuciano Coelho return ret; 468*90921014SLuciano Coelho } 469*90921014SLuciano Coelho 470*90921014SLuciano Coelho int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) 471*90921014SLuciano Coelho { 472*90921014SLuciano Coelho struct acx_rts_threshold *rts; 473*90921014SLuciano Coelho int ret; 474*90921014SLuciano Coelho 475*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx rts threshold"); 476*90921014SLuciano Coelho 477*90921014SLuciano Coelho rts = kzalloc(sizeof(*rts), GFP_KERNEL); 478*90921014SLuciano Coelho if (!rts) { 479*90921014SLuciano Coelho ret = -ENOMEM; 480*90921014SLuciano Coelho goto out; 481*90921014SLuciano Coelho } 482*90921014SLuciano Coelho 483*90921014SLuciano Coelho rts->threshold = rts_threshold; 484*90921014SLuciano Coelho 485*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); 486*90921014SLuciano Coelho if (ret < 0) { 487*90921014SLuciano Coelho wl1251_warning("failed to set rts threshold: %d", ret); 488*90921014SLuciano Coelho goto out; 489*90921014SLuciano Coelho } 490*90921014SLuciano Coelho 491*90921014SLuciano Coelho out: 492*90921014SLuciano Coelho kfree(rts); 493*90921014SLuciano Coelho return ret; 494*90921014SLuciano Coelho } 495*90921014SLuciano Coelho 496*90921014SLuciano Coelho int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) 497*90921014SLuciano Coelho { 498*90921014SLuciano Coelho struct acx_beacon_filter_option *beacon_filter; 499*90921014SLuciano Coelho int ret; 500*90921014SLuciano Coelho 501*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); 502*90921014SLuciano Coelho 503*90921014SLuciano Coelho beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); 504*90921014SLuciano Coelho if (!beacon_filter) { 505*90921014SLuciano Coelho ret = -ENOMEM; 506*90921014SLuciano Coelho goto out; 507*90921014SLuciano Coelho } 508*90921014SLuciano Coelho 509*90921014SLuciano Coelho beacon_filter->enable = enable_filter; 510*90921014SLuciano Coelho beacon_filter->max_num_beacons = 0; 511*90921014SLuciano Coelho 512*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, 513*90921014SLuciano Coelho beacon_filter, sizeof(*beacon_filter)); 514*90921014SLuciano Coelho if (ret < 0) { 515*90921014SLuciano Coelho wl1251_warning("failed to set beacon filter opt: %d", ret); 516*90921014SLuciano Coelho goto out; 517*90921014SLuciano Coelho } 518*90921014SLuciano Coelho 519*90921014SLuciano Coelho out: 520*90921014SLuciano Coelho kfree(beacon_filter); 521*90921014SLuciano Coelho return ret; 522*90921014SLuciano Coelho } 523*90921014SLuciano Coelho 524*90921014SLuciano Coelho int wl1251_acx_beacon_filter_table(struct wl1251 *wl) 525*90921014SLuciano Coelho { 526*90921014SLuciano Coelho struct acx_beacon_filter_ie_table *ie_table; 527*90921014SLuciano Coelho int idx = 0; 528*90921014SLuciano Coelho int ret; 529*90921014SLuciano Coelho 530*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx beacon filter table"); 531*90921014SLuciano Coelho 532*90921014SLuciano Coelho ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); 533*90921014SLuciano Coelho if (!ie_table) { 534*90921014SLuciano Coelho ret = -ENOMEM; 535*90921014SLuciano Coelho goto out; 536*90921014SLuciano Coelho } 537*90921014SLuciano Coelho 538*90921014SLuciano Coelho /* configure default beacon pass-through rules */ 539*90921014SLuciano Coelho ie_table->num_ie = 1; 540*90921014SLuciano Coelho ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; 541*90921014SLuciano Coelho ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; 542*90921014SLuciano Coelho 543*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, 544*90921014SLuciano Coelho ie_table, sizeof(*ie_table)); 545*90921014SLuciano Coelho if (ret < 0) { 546*90921014SLuciano Coelho wl1251_warning("failed to set beacon filter table: %d", ret); 547*90921014SLuciano Coelho goto out; 548*90921014SLuciano Coelho } 549*90921014SLuciano Coelho 550*90921014SLuciano Coelho out: 551*90921014SLuciano Coelho kfree(ie_table); 552*90921014SLuciano Coelho return ret; 553*90921014SLuciano Coelho } 554*90921014SLuciano Coelho 555*90921014SLuciano Coelho int wl1251_acx_conn_monit_params(struct wl1251 *wl) 556*90921014SLuciano Coelho { 557*90921014SLuciano Coelho struct acx_conn_monit_params *acx; 558*90921014SLuciano Coelho int ret; 559*90921014SLuciano Coelho 560*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); 561*90921014SLuciano Coelho 562*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 563*90921014SLuciano Coelho if (!acx) { 564*90921014SLuciano Coelho ret = -ENOMEM; 565*90921014SLuciano Coelho goto out; 566*90921014SLuciano Coelho } 567*90921014SLuciano Coelho 568*90921014SLuciano Coelho acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; 569*90921014SLuciano Coelho acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; 570*90921014SLuciano Coelho 571*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, 572*90921014SLuciano Coelho acx, sizeof(*acx)); 573*90921014SLuciano Coelho if (ret < 0) { 574*90921014SLuciano Coelho wl1251_warning("failed to set connection monitor " 575*90921014SLuciano Coelho "parameters: %d", ret); 576*90921014SLuciano Coelho goto out; 577*90921014SLuciano Coelho } 578*90921014SLuciano Coelho 579*90921014SLuciano Coelho out: 580*90921014SLuciano Coelho kfree(acx); 581*90921014SLuciano Coelho return ret; 582*90921014SLuciano Coelho } 583*90921014SLuciano Coelho 584*90921014SLuciano Coelho int wl1251_acx_sg_enable(struct wl1251 *wl) 585*90921014SLuciano Coelho { 586*90921014SLuciano Coelho struct acx_bt_wlan_coex *pta; 587*90921014SLuciano Coelho int ret; 588*90921014SLuciano Coelho 589*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx sg enable"); 590*90921014SLuciano Coelho 591*90921014SLuciano Coelho pta = kzalloc(sizeof(*pta), GFP_KERNEL); 592*90921014SLuciano Coelho if (!pta) { 593*90921014SLuciano Coelho ret = -ENOMEM; 594*90921014SLuciano Coelho goto out; 595*90921014SLuciano Coelho } 596*90921014SLuciano Coelho 597*90921014SLuciano Coelho pta->enable = SG_ENABLE; 598*90921014SLuciano Coelho 599*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); 600*90921014SLuciano Coelho if (ret < 0) { 601*90921014SLuciano Coelho wl1251_warning("failed to set softgemini enable: %d", ret); 602*90921014SLuciano Coelho goto out; 603*90921014SLuciano Coelho } 604*90921014SLuciano Coelho 605*90921014SLuciano Coelho out: 606*90921014SLuciano Coelho kfree(pta); 607*90921014SLuciano Coelho return ret; 608*90921014SLuciano Coelho } 609*90921014SLuciano Coelho 610*90921014SLuciano Coelho int wl1251_acx_sg_cfg(struct wl1251 *wl) 611*90921014SLuciano Coelho { 612*90921014SLuciano Coelho struct acx_bt_wlan_coex_param *param; 613*90921014SLuciano Coelho int ret; 614*90921014SLuciano Coelho 615*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx sg cfg"); 616*90921014SLuciano Coelho 617*90921014SLuciano Coelho param = kzalloc(sizeof(*param), GFP_KERNEL); 618*90921014SLuciano Coelho if (!param) { 619*90921014SLuciano Coelho ret = -ENOMEM; 620*90921014SLuciano Coelho goto out; 621*90921014SLuciano Coelho } 622*90921014SLuciano Coelho 623*90921014SLuciano Coelho /* BT-WLAN coext parameters */ 624*90921014SLuciano Coelho param->min_rate = RATE_INDEX_24MBPS; 625*90921014SLuciano Coelho param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; 626*90921014SLuciano Coelho param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; 627*90921014SLuciano Coelho param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; 628*90921014SLuciano Coelho param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; 629*90921014SLuciano Coelho param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; 630*90921014SLuciano Coelho param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; 631*90921014SLuciano Coelho param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; 632*90921014SLuciano Coelho param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; 633*90921014SLuciano Coelho param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; 634*90921014SLuciano Coelho param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; 635*90921014SLuciano Coelho param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; 636*90921014SLuciano Coelho param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; 637*90921014SLuciano Coelho param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; 638*90921014SLuciano Coelho param->antenna_type = PTA_ANTENNA_TYPE_DEF; 639*90921014SLuciano Coelho param->signal_type = PTA_SIGNALING_TYPE_DEF; 640*90921014SLuciano Coelho param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; 641*90921014SLuciano Coelho param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; 642*90921014SLuciano Coelho param->max_cts = PTA_MAX_NUM_CTS_DEF; 643*90921014SLuciano Coelho param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; 644*90921014SLuciano Coelho param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; 645*90921014SLuciano Coelho param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; 646*90921014SLuciano Coelho param->wlan_elp_hp = PTA_ELP_HP_DEF; 647*90921014SLuciano Coelho param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; 648*90921014SLuciano Coelho param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; 649*90921014SLuciano Coelho param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; 650*90921014SLuciano Coelho param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; 651*90921014SLuciano Coelho param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; 652*90921014SLuciano Coelho 653*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); 654*90921014SLuciano Coelho if (ret < 0) { 655*90921014SLuciano Coelho wl1251_warning("failed to set sg config: %d", ret); 656*90921014SLuciano Coelho goto out; 657*90921014SLuciano Coelho } 658*90921014SLuciano Coelho 659*90921014SLuciano Coelho out: 660*90921014SLuciano Coelho kfree(param); 661*90921014SLuciano Coelho return ret; 662*90921014SLuciano Coelho } 663*90921014SLuciano Coelho 664*90921014SLuciano Coelho int wl1251_acx_cca_threshold(struct wl1251 *wl) 665*90921014SLuciano Coelho { 666*90921014SLuciano Coelho struct acx_energy_detection *detection; 667*90921014SLuciano Coelho int ret; 668*90921014SLuciano Coelho 669*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx cca threshold"); 670*90921014SLuciano Coelho 671*90921014SLuciano Coelho detection = kzalloc(sizeof(*detection), GFP_KERNEL); 672*90921014SLuciano Coelho if (!detection) { 673*90921014SLuciano Coelho ret = -ENOMEM; 674*90921014SLuciano Coelho goto out; 675*90921014SLuciano Coelho } 676*90921014SLuciano Coelho 677*90921014SLuciano Coelho detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; 678*90921014SLuciano Coelho detection->tx_energy_detection = 0; 679*90921014SLuciano Coelho 680*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, 681*90921014SLuciano Coelho detection, sizeof(*detection)); 682*90921014SLuciano Coelho if (ret < 0) 683*90921014SLuciano Coelho wl1251_warning("failed to set cca threshold: %d", ret); 684*90921014SLuciano Coelho 685*90921014SLuciano Coelho out: 686*90921014SLuciano Coelho kfree(detection); 687*90921014SLuciano Coelho return ret; 688*90921014SLuciano Coelho } 689*90921014SLuciano Coelho 690*90921014SLuciano Coelho int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) 691*90921014SLuciano Coelho { 692*90921014SLuciano Coelho struct acx_beacon_broadcast *bb; 693*90921014SLuciano Coelho int ret; 694*90921014SLuciano Coelho 695*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); 696*90921014SLuciano Coelho 697*90921014SLuciano Coelho bb = kzalloc(sizeof(*bb), GFP_KERNEL); 698*90921014SLuciano Coelho if (!bb) { 699*90921014SLuciano Coelho ret = -ENOMEM; 700*90921014SLuciano Coelho goto out; 701*90921014SLuciano Coelho } 702*90921014SLuciano Coelho 703*90921014SLuciano Coelho bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; 704*90921014SLuciano Coelho bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; 705*90921014SLuciano Coelho bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; 706*90921014SLuciano Coelho bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; 707*90921014SLuciano Coelho 708*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); 709*90921014SLuciano Coelho if (ret < 0) { 710*90921014SLuciano Coelho wl1251_warning("failed to set rx config: %d", ret); 711*90921014SLuciano Coelho goto out; 712*90921014SLuciano Coelho } 713*90921014SLuciano Coelho 714*90921014SLuciano Coelho out: 715*90921014SLuciano Coelho kfree(bb); 716*90921014SLuciano Coelho return ret; 717*90921014SLuciano Coelho } 718*90921014SLuciano Coelho 719*90921014SLuciano Coelho int wl1251_acx_aid(struct wl1251 *wl, u16 aid) 720*90921014SLuciano Coelho { 721*90921014SLuciano Coelho struct acx_aid *acx_aid; 722*90921014SLuciano Coelho int ret; 723*90921014SLuciano Coelho 724*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx aid"); 725*90921014SLuciano Coelho 726*90921014SLuciano Coelho acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); 727*90921014SLuciano Coelho if (!acx_aid) { 728*90921014SLuciano Coelho ret = -ENOMEM; 729*90921014SLuciano Coelho goto out; 730*90921014SLuciano Coelho } 731*90921014SLuciano Coelho 732*90921014SLuciano Coelho acx_aid->aid = aid; 733*90921014SLuciano Coelho 734*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); 735*90921014SLuciano Coelho if (ret < 0) { 736*90921014SLuciano Coelho wl1251_warning("failed to set aid: %d", ret); 737*90921014SLuciano Coelho goto out; 738*90921014SLuciano Coelho } 739*90921014SLuciano Coelho 740*90921014SLuciano Coelho out: 741*90921014SLuciano Coelho kfree(acx_aid); 742*90921014SLuciano Coelho return ret; 743*90921014SLuciano Coelho } 744*90921014SLuciano Coelho 745*90921014SLuciano Coelho int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) 746*90921014SLuciano Coelho { 747*90921014SLuciano Coelho struct acx_event_mask *mask; 748*90921014SLuciano Coelho int ret; 749*90921014SLuciano Coelho 750*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx event mbox mask"); 751*90921014SLuciano Coelho 752*90921014SLuciano Coelho mask = kzalloc(sizeof(*mask), GFP_KERNEL); 753*90921014SLuciano Coelho if (!mask) { 754*90921014SLuciano Coelho ret = -ENOMEM; 755*90921014SLuciano Coelho goto out; 756*90921014SLuciano Coelho } 757*90921014SLuciano Coelho 758*90921014SLuciano Coelho /* high event mask is unused */ 759*90921014SLuciano Coelho mask->high_event_mask = 0xffffffff; 760*90921014SLuciano Coelho 761*90921014SLuciano Coelho mask->event_mask = event_mask; 762*90921014SLuciano Coelho 763*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, 764*90921014SLuciano Coelho mask, sizeof(*mask)); 765*90921014SLuciano Coelho if (ret < 0) { 766*90921014SLuciano Coelho wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); 767*90921014SLuciano Coelho goto out; 768*90921014SLuciano Coelho } 769*90921014SLuciano Coelho 770*90921014SLuciano Coelho out: 771*90921014SLuciano Coelho kfree(mask); 772*90921014SLuciano Coelho return ret; 773*90921014SLuciano Coelho } 774*90921014SLuciano Coelho 775*90921014SLuciano Coelho int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, 776*90921014SLuciano Coelho u8 depth, enum wl1251_acx_low_rssi_type type) 777*90921014SLuciano Coelho { 778*90921014SLuciano Coelho struct acx_low_rssi *rssi; 779*90921014SLuciano Coelho int ret; 780*90921014SLuciano Coelho 781*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx low rssi"); 782*90921014SLuciano Coelho 783*90921014SLuciano Coelho rssi = kzalloc(sizeof(*rssi), GFP_KERNEL); 784*90921014SLuciano Coelho if (!rssi) 785*90921014SLuciano Coelho return -ENOMEM; 786*90921014SLuciano Coelho 787*90921014SLuciano Coelho rssi->threshold = threshold; 788*90921014SLuciano Coelho rssi->weight = weight; 789*90921014SLuciano Coelho rssi->depth = depth; 790*90921014SLuciano Coelho rssi->type = type; 791*90921014SLuciano Coelho 792*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi)); 793*90921014SLuciano Coelho if (ret < 0) 794*90921014SLuciano Coelho wl1251_warning("failed to set low rssi threshold: %d", ret); 795*90921014SLuciano Coelho 796*90921014SLuciano Coelho kfree(rssi); 797*90921014SLuciano Coelho return ret; 798*90921014SLuciano Coelho } 799*90921014SLuciano Coelho 800*90921014SLuciano Coelho int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) 801*90921014SLuciano Coelho { 802*90921014SLuciano Coelho struct acx_preamble *acx; 803*90921014SLuciano Coelho int ret; 804*90921014SLuciano Coelho 805*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx_set_preamble"); 806*90921014SLuciano Coelho 807*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 808*90921014SLuciano Coelho if (!acx) { 809*90921014SLuciano Coelho ret = -ENOMEM; 810*90921014SLuciano Coelho goto out; 811*90921014SLuciano Coelho } 812*90921014SLuciano Coelho 813*90921014SLuciano Coelho acx->preamble = preamble; 814*90921014SLuciano Coelho 815*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); 816*90921014SLuciano Coelho if (ret < 0) { 817*90921014SLuciano Coelho wl1251_warning("Setting of preamble failed: %d", ret); 818*90921014SLuciano Coelho goto out; 819*90921014SLuciano Coelho } 820*90921014SLuciano Coelho 821*90921014SLuciano Coelho out: 822*90921014SLuciano Coelho kfree(acx); 823*90921014SLuciano Coelho return ret; 824*90921014SLuciano Coelho } 825*90921014SLuciano Coelho 826*90921014SLuciano Coelho int wl1251_acx_cts_protect(struct wl1251 *wl, 827*90921014SLuciano Coelho enum acx_ctsprotect_type ctsprotect) 828*90921014SLuciano Coelho { 829*90921014SLuciano Coelho struct acx_ctsprotect *acx; 830*90921014SLuciano Coelho int ret; 831*90921014SLuciano Coelho 832*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); 833*90921014SLuciano Coelho 834*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 835*90921014SLuciano Coelho if (!acx) { 836*90921014SLuciano Coelho ret = -ENOMEM; 837*90921014SLuciano Coelho goto out; 838*90921014SLuciano Coelho } 839*90921014SLuciano Coelho 840*90921014SLuciano Coelho acx->ctsprotect = ctsprotect; 841*90921014SLuciano Coelho 842*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); 843*90921014SLuciano Coelho if (ret < 0) { 844*90921014SLuciano Coelho wl1251_warning("Setting of ctsprotect failed: %d", ret); 845*90921014SLuciano Coelho goto out; 846*90921014SLuciano Coelho } 847*90921014SLuciano Coelho 848*90921014SLuciano Coelho out: 849*90921014SLuciano Coelho kfree(acx); 850*90921014SLuciano Coelho return ret; 851*90921014SLuciano Coelho } 852*90921014SLuciano Coelho 853*90921014SLuciano Coelho int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) 854*90921014SLuciano Coelho { 855*90921014SLuciano Coelho struct acx_tsf_info *tsf_info; 856*90921014SLuciano Coelho int ret; 857*90921014SLuciano Coelho 858*90921014SLuciano Coelho tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); 859*90921014SLuciano Coelho if (!tsf_info) { 860*90921014SLuciano Coelho ret = -ENOMEM; 861*90921014SLuciano Coelho goto out; 862*90921014SLuciano Coelho } 863*90921014SLuciano Coelho 864*90921014SLuciano Coelho ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, 865*90921014SLuciano Coelho tsf_info, sizeof(*tsf_info)); 866*90921014SLuciano Coelho if (ret < 0) { 867*90921014SLuciano Coelho wl1251_warning("ACX_FW_REV interrogate failed"); 868*90921014SLuciano Coelho goto out; 869*90921014SLuciano Coelho } 870*90921014SLuciano Coelho 871*90921014SLuciano Coelho *mactime = tsf_info->current_tsf_lsb | 872*90921014SLuciano Coelho (tsf_info->current_tsf_msb << 31); 873*90921014SLuciano Coelho 874*90921014SLuciano Coelho out: 875*90921014SLuciano Coelho kfree(tsf_info); 876*90921014SLuciano Coelho return ret; 877*90921014SLuciano Coelho } 878*90921014SLuciano Coelho 879*90921014SLuciano Coelho int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) 880*90921014SLuciano Coelho { 881*90921014SLuciano Coelho int ret; 882*90921014SLuciano Coelho 883*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx statistics"); 884*90921014SLuciano Coelho 885*90921014SLuciano Coelho ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, 886*90921014SLuciano Coelho sizeof(*stats)); 887*90921014SLuciano Coelho if (ret < 0) { 888*90921014SLuciano Coelho wl1251_warning("acx statistics failed: %d", ret); 889*90921014SLuciano Coelho return -ENOMEM; 890*90921014SLuciano Coelho } 891*90921014SLuciano Coelho 892*90921014SLuciano Coelho return 0; 893*90921014SLuciano Coelho } 894*90921014SLuciano Coelho 895*90921014SLuciano Coelho int wl1251_acx_rate_policies(struct wl1251 *wl) 896*90921014SLuciano Coelho { 897*90921014SLuciano Coelho struct acx_rate_policy *acx; 898*90921014SLuciano Coelho int ret = 0; 899*90921014SLuciano Coelho 900*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx rate policies"); 901*90921014SLuciano Coelho 902*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 903*90921014SLuciano Coelho 904*90921014SLuciano Coelho if (!acx) { 905*90921014SLuciano Coelho ret = -ENOMEM; 906*90921014SLuciano Coelho goto out; 907*90921014SLuciano Coelho } 908*90921014SLuciano Coelho 909*90921014SLuciano Coelho /* configure one default (one-size-fits-all) rate class */ 910*90921014SLuciano Coelho acx->rate_class_cnt = 1; 911*90921014SLuciano Coelho acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; 912*90921014SLuciano Coelho acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; 913*90921014SLuciano Coelho acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; 914*90921014SLuciano Coelho acx->rate_class[0].aflags = 0; 915*90921014SLuciano Coelho 916*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); 917*90921014SLuciano Coelho if (ret < 0) { 918*90921014SLuciano Coelho wl1251_warning("Setting of rate policies failed: %d", ret); 919*90921014SLuciano Coelho goto out; 920*90921014SLuciano Coelho } 921*90921014SLuciano Coelho 922*90921014SLuciano Coelho out: 923*90921014SLuciano Coelho kfree(acx); 924*90921014SLuciano Coelho return ret; 925*90921014SLuciano Coelho } 926*90921014SLuciano Coelho 927*90921014SLuciano Coelho int wl1251_acx_mem_cfg(struct wl1251 *wl) 928*90921014SLuciano Coelho { 929*90921014SLuciano Coelho struct wl1251_acx_config_memory *mem_conf; 930*90921014SLuciano Coelho int ret, i; 931*90921014SLuciano Coelho 932*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx mem cfg"); 933*90921014SLuciano Coelho 934*90921014SLuciano Coelho mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); 935*90921014SLuciano Coelho if (!mem_conf) { 936*90921014SLuciano Coelho ret = -ENOMEM; 937*90921014SLuciano Coelho goto out; 938*90921014SLuciano Coelho } 939*90921014SLuciano Coelho 940*90921014SLuciano Coelho /* memory config */ 941*90921014SLuciano Coelho mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); 942*90921014SLuciano Coelho mem_conf->mem_config.rx_mem_block_num = 35; 943*90921014SLuciano Coelho mem_conf->mem_config.tx_min_mem_block_num = 64; 944*90921014SLuciano Coelho mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; 945*90921014SLuciano Coelho mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; 946*90921014SLuciano Coelho mem_conf->mem_config.num_ssid_profiles = 1; 947*90921014SLuciano Coelho mem_conf->mem_config.debug_buffer_size = 948*90921014SLuciano Coelho cpu_to_le16(TRACE_BUFFER_MAX_SIZE); 949*90921014SLuciano Coelho 950*90921014SLuciano Coelho /* RX queue config */ 951*90921014SLuciano Coelho mem_conf->rx_queue_config.dma_address = 0; 952*90921014SLuciano Coelho mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; 953*90921014SLuciano Coelho mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; 954*90921014SLuciano Coelho mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; 955*90921014SLuciano Coelho 956*90921014SLuciano Coelho /* TX queue config */ 957*90921014SLuciano Coelho for (i = 0; i < MAX_TX_QUEUES; i++) { 958*90921014SLuciano Coelho mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; 959*90921014SLuciano Coelho mem_conf->tx_queue_config[i].attributes = i; 960*90921014SLuciano Coelho } 961*90921014SLuciano Coelho 962*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, 963*90921014SLuciano Coelho sizeof(*mem_conf)); 964*90921014SLuciano Coelho if (ret < 0) { 965*90921014SLuciano Coelho wl1251_warning("wl1251 mem config failed: %d", ret); 966*90921014SLuciano Coelho goto out; 967*90921014SLuciano Coelho } 968*90921014SLuciano Coelho 969*90921014SLuciano Coelho out: 970*90921014SLuciano Coelho kfree(mem_conf); 971*90921014SLuciano Coelho return ret; 972*90921014SLuciano Coelho } 973*90921014SLuciano Coelho 974*90921014SLuciano Coelho int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) 975*90921014SLuciano Coelho { 976*90921014SLuciano Coelho struct wl1251_acx_wr_tbtt_and_dtim *acx; 977*90921014SLuciano Coelho int ret; 978*90921014SLuciano Coelho 979*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); 980*90921014SLuciano Coelho 981*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 982*90921014SLuciano Coelho if (!acx) { 983*90921014SLuciano Coelho ret = -ENOMEM; 984*90921014SLuciano Coelho goto out; 985*90921014SLuciano Coelho } 986*90921014SLuciano Coelho 987*90921014SLuciano Coelho acx->tbtt = tbtt; 988*90921014SLuciano Coelho acx->dtim = dtim; 989*90921014SLuciano Coelho 990*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, 991*90921014SLuciano Coelho acx, sizeof(*acx)); 992*90921014SLuciano Coelho if (ret < 0) { 993*90921014SLuciano Coelho wl1251_warning("failed to set tbtt and dtim: %d", ret); 994*90921014SLuciano Coelho goto out; 995*90921014SLuciano Coelho } 996*90921014SLuciano Coelho 997*90921014SLuciano Coelho out: 998*90921014SLuciano Coelho kfree(acx); 999*90921014SLuciano Coelho return ret; 1000*90921014SLuciano Coelho } 1001*90921014SLuciano Coelho 1002*90921014SLuciano Coelho int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, 1003*90921014SLuciano Coelho u8 max_consecutive) 1004*90921014SLuciano Coelho { 1005*90921014SLuciano Coelho struct wl1251_acx_bet_enable *acx; 1006*90921014SLuciano Coelho int ret; 1007*90921014SLuciano Coelho 1008*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx bet enable"); 1009*90921014SLuciano Coelho 1010*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1011*90921014SLuciano Coelho if (!acx) { 1012*90921014SLuciano Coelho ret = -ENOMEM; 1013*90921014SLuciano Coelho goto out; 1014*90921014SLuciano Coelho } 1015*90921014SLuciano Coelho 1016*90921014SLuciano Coelho acx->enable = mode; 1017*90921014SLuciano Coelho acx->max_consecutive = max_consecutive; 1018*90921014SLuciano Coelho 1019*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); 1020*90921014SLuciano Coelho if (ret < 0) { 1021*90921014SLuciano Coelho wl1251_warning("wl1251 acx bet enable failed: %d", ret); 1022*90921014SLuciano Coelho goto out; 1023*90921014SLuciano Coelho } 1024*90921014SLuciano Coelho 1025*90921014SLuciano Coelho out: 1026*90921014SLuciano Coelho kfree(acx); 1027*90921014SLuciano Coelho return ret; 1028*90921014SLuciano Coelho } 1029*90921014SLuciano Coelho 1030*90921014SLuciano Coelho int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, 1031*90921014SLuciano Coelho u8 aifs, u16 txop) 1032*90921014SLuciano Coelho { 1033*90921014SLuciano Coelho struct wl1251_acx_ac_cfg *acx; 1034*90921014SLuciano Coelho int ret = 0; 1035*90921014SLuciano Coelho 1036*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " 1037*90921014SLuciano Coelho "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); 1038*90921014SLuciano Coelho 1039*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1040*90921014SLuciano Coelho 1041*90921014SLuciano Coelho if (!acx) { 1042*90921014SLuciano Coelho ret = -ENOMEM; 1043*90921014SLuciano Coelho goto out; 1044*90921014SLuciano Coelho } 1045*90921014SLuciano Coelho 1046*90921014SLuciano Coelho acx->ac = ac; 1047*90921014SLuciano Coelho acx->cw_min = cw_min; 1048*90921014SLuciano Coelho acx->cw_max = cw_max; 1049*90921014SLuciano Coelho acx->aifsn = aifs; 1050*90921014SLuciano Coelho acx->txop_limit = txop; 1051*90921014SLuciano Coelho 1052*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); 1053*90921014SLuciano Coelho if (ret < 0) { 1054*90921014SLuciano Coelho wl1251_warning("acx ac cfg failed: %d", ret); 1055*90921014SLuciano Coelho goto out; 1056*90921014SLuciano Coelho } 1057*90921014SLuciano Coelho 1058*90921014SLuciano Coelho out: 1059*90921014SLuciano Coelho kfree(acx); 1060*90921014SLuciano Coelho return ret; 1061*90921014SLuciano Coelho } 1062*90921014SLuciano Coelho 1063*90921014SLuciano Coelho int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, 1064*90921014SLuciano Coelho enum wl1251_acx_channel_type type, 1065*90921014SLuciano Coelho u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, 1066*90921014SLuciano Coelho enum wl1251_acx_ack_policy ack_policy) 1067*90921014SLuciano Coelho { 1068*90921014SLuciano Coelho struct wl1251_acx_tid_cfg *acx; 1069*90921014SLuciano Coelho int ret = 0; 1070*90921014SLuciano Coelho 1071*90921014SLuciano Coelho wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " 1072*90921014SLuciano Coelho "ps_scheme %d ack_policy %d", queue, type, tsid, 1073*90921014SLuciano Coelho ps_scheme, ack_policy); 1074*90921014SLuciano Coelho 1075*90921014SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1076*90921014SLuciano Coelho 1077*90921014SLuciano Coelho if (!acx) { 1078*90921014SLuciano Coelho ret = -ENOMEM; 1079*90921014SLuciano Coelho goto out; 1080*90921014SLuciano Coelho } 1081*90921014SLuciano Coelho 1082*90921014SLuciano Coelho acx->queue = queue; 1083*90921014SLuciano Coelho acx->type = type; 1084*90921014SLuciano Coelho acx->tsid = tsid; 1085*90921014SLuciano Coelho acx->ps_scheme = ps_scheme; 1086*90921014SLuciano Coelho acx->ack_policy = ack_policy; 1087*90921014SLuciano Coelho 1088*90921014SLuciano Coelho ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); 1089*90921014SLuciano Coelho if (ret < 0) { 1090*90921014SLuciano Coelho wl1251_warning("acx tid cfg failed: %d", ret); 1091*90921014SLuciano Coelho goto out; 1092*90921014SLuciano Coelho } 1093*90921014SLuciano Coelho 1094*90921014SLuciano Coelho out: 1095*90921014SLuciano Coelho kfree(acx); 1096*90921014SLuciano Coelho return ret; 1097*90921014SLuciano Coelho } 1098