static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, u8 beacon) { memset(status, 0, sizeof(struct ieee80211_rx_status)); if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) status->band = IEEE80211_BAND_2GHZ; else status->band = IEEE80211_BAND_5GHZ; status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band); /* 11n support */ if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; /* * Read the signal level and antenna diversity indication. * The msb in the signal level is always set as it is a * negative number. * The antenna indication is the msb of the rssi. */ status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we * need to divide by two for now, but TI has been discussing about * changing it. This needs to be rechecked. */ wl->noise = desc->rssi - (desc->snr >> 1); status->freq = ieee80211_channel_to_frequency(desc->channel, status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) { status->flag |= RX_FLAG_MMIC_ERROR; wl1271_warning("Michael MIC error. Desc: 0x%x", desc_err_code); } } if (beacon) wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, status->band); }
int wl1271_acx_beacon_filter_table(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct acx_beacon_filter_ie_table *ie_table; int i, idx = 0; int ret; bool vendor_spec = false; wl1271_debug(DEBUG_ACX, "acx beacon filter table"); ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); if (!ie_table) { ret = -ENOMEM; goto out; } /* configure default beacon pass-through rules */ ie_table->role_id = wlvif->role_id; ie_table->num_ie = 0; for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); ie_table->table[idx++] = r->ie; ie_table->table[idx++] = r->rule; if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { /* only one vendor specific ie allowed */ if (vendor_spec) continue; /* for vendor specific rules configure the additional fields */ memcpy(&(ie_table->table[idx]), r->oui, CONF_BCN_IE_OUI_LEN); idx += CONF_BCN_IE_OUI_LEN; ie_table->table[idx++] = r->type; memcpy(&(ie_table->table[idx]), r->version, CONF_BCN_IE_VER_LEN); idx += CONF_BCN_IE_VER_LEN; vendor_spec = true; } ie_table->num_ie++; } ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); if (ret < 0) { wl1271_warning("failed to set beacon filter table: %d", ret); goto out; } out: kfree(ie_table); return ret; }
static ssize_t rx_streaming_always_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; char buf[10]; size_t len; unsigned long value; int ret; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; ret = strict_strtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_write!"); return -EINVAL; } /* valid values: 0, 10-100 */ if (!(value == 0 || value == 1)) { wl1271_warning("value is not in valid!"); return -EINVAL; } mutex_lock(&wl->mutex); wl->conf.rx_streaming.always = value; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; wl1271_recalc_rx_streaming(wl); wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); return count; }
static ssize_t beacon_interval_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; char buf[10]; size_t len; unsigned long value; int ret; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_interval"); return -EINVAL; } if (value < 1 || value > 255) { wl1271_warning("beacon interval value is not in valid range"); return -ERANGE; } mutex_lock(&wl->mutex); wl->conf.conn.listen_interval = value; /* for some reason there are different event types for 1 and >1 */ if (value == 1) wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON; else wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS; /* * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only * take effect on the next time we enter psm. */ mutex_unlock(&wl->mutex); return count; }
/* setup BA session receiver setting in the FW. */ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable, u8 peer_hlid, u8 win_size) { struct wl1271_acx_ba_receiver_setup *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } acx->hlid = peer_hlid; acx->tid = tid_index; acx->enable = enable; acx->win_size = win_size; acx->ssn = ssn; ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx, sizeof(*acx), BIT(CMD_STATUS_NO_RX_BA_SESSION)); if (ret < 0) { wl1271_warning("acx ba receiver session failed: %d", ret); goto out; } /* sometimes we can't start the session */ if (ret == CMD_STATUS_NO_RX_BA_SESSION) { wl1271_warning("no fw rx ba on tid %d", tid_index); ret = -EBUSY; goto out; } ret = 0; out: kfree(acx); return ret; }
static void wl1271_tx_complete_packet(struct wl1271 *wl, struct wl1271_tx_hw_res_descr *result) { struct ieee80211_tx_info *info; struct sk_buff *skb; u32 header_len; int id = result->id; /* check for id legality */ if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { wl1271_warning("TX result illegal id: %d", id); return; } skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); /* update packet status */ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (result->status == TX_SUCCESS) info->flags |= IEEE80211_TX_STAT_ACK; if (result->status & TX_RETRY_EXCEEDED) { /* FIXME */ /* info->status.excessive_retries = 1; */ wl->stats.excessive_retries++; } } /* FIXME */ /* info->status.retry_count = result->ack_failures; */ wl->stats.retry_count += result->ack_failures; /* get header len */ if (info->control.hw_key && info->control.hw_key->alg == ALG_TKIP) header_len = WL1271_TKIP_IV_SPACE + sizeof(struct wl1271_tx_hw_descr); else header_len = sizeof(struct wl1271_tx_hw_descr); wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" " status 0x%x", result->id, skb, result->ack_failures, result->rate_class_index, result->status); /* remove private header from packet */ skb_pull(skb, header_len); /* return the packet to the stack */ ieee80211_tx_status(wl->hw, skb); wl->tx_frames[result->id] = NULL; }
static ssize_t sleep_auth_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; unsigned long value; int ret; ret = kstrtoul_from_user(user_buf, count, 0, &value); if (ret < 0) { wl1271_warning("illegal value in sleep_auth"); return -EINVAL; } if (value < 0 || value > WL1271_PSM_MAX) { wl1271_warning("sleep_auth must be between 0 and %d", WL1271_PSM_MAX); return -ERANGE; } mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; ret = wl1271_acx_sleep_auth(wl, value); if (ret < 0) goto out_sleep; out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); return count; }
static ssize_t fwlog_enable_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; char buf[16]; size_t len; unsigned long value; int ret; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value for fwlog_enable"); return -EINVAL; } if (value > 1) { wl1271_warning("fwlog_enable value is not in valid range"); return -ERANGE; } wl1271_warning("FW log options will take effect after the FW reboots"); mutex_lock(&wl->mutex); if (value) wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_HOST; else wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; mutex_unlock(&wl->mutex); return count; }
static ssize_t radar_debug_mode_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; struct wl12xx_vif *wlvif; unsigned long value; int ret; ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in radar_debug_mode!"); return -EINVAL; } /* valid values: 0/1 */ if (!(value == 0 || value == 1)) { wl1271_warning("value is not in valid!"); return -EINVAL; } mutex_lock(&wl->mutex); wl->radar_debug_mode = value; if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; wl12xx_for_each_wlvif_ap(wl, wlvif) { wlcore_cmd_generic_cfg(wl, wlvif, WLCORE_CFG_FEATURE_RADAR_DEBUG, wl->radar_debug_mode, 0); }
/* Configure BA session initiator/receiver parameters setting in the FW. */ int wl1271_acx_set_ba_session(struct wl1271 *wl, enum ieee80211_back_parties direction, u8 tid_index, u8 policy) { struct wl1271_acx_ba_session_policy *acx; int ret; wl1271_debug(DEBUG_ACX, "acx ba session setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* ANY role */ acx->role_id = 0xff; acx->tid = tid_index; acx->enable = policy; acx->ba_direction = direction; switch (direction) { case WLAN_BACK_INITIATOR: acx->win_size = wl->conf.ht.tx_ba_win_size; acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; break; case WLAN_BACK_RECIPIENT: acx->win_size = RX_BA_WIN_SIZE; acx->inactivity_timeout = 0; break; default: wl1271_error("Incorrect acx command id=%x\n", direction); ret = -EINVAL; goto out; } ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_POLICY_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ba session setting failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool enable) { struct acx_conn_monit_params *acx; u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; int ret; //HTC_WIFI_START if(enable) printk("wl1271_acx_conn_monit_params enable = true\n"); else printk("wl1271_acx_conn_monit_params enable = false\n"); //HTC_WIFI_END wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", enable ? "enabled" : "disabled"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } if (enable) { threshold = wl->conf.conn.synch_fail_thold; timeout = wl->conf.conn.bss_lose_timeout; //HTC_WIFI_START printk("beacon miss threshold = %d\n",threshold); printk("timeout = %d\n",timeout); //HTC_WIFI_END } acx->role_id = wlvif->role_id; acx->synch_fail_thold = cpu_to_le32(threshold); acx->bss_lose_timeout = cpu_to_le32(timeout); ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("failed to set connection monitor " "parameters: %d", ret); goto out; } out: kfree(acx); return ret; }
/* Configure or disable a specific RX filter pattern */ int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, struct wl12xx_rx_filter *filter) { struct acx_rx_filter_cfg *acx; int fields_size = 0; int acx_size; int ret; WARN_ON(enable && !filter); WARN_ON(index >= WL1271_MAX_RX_FILTERS); wl1271_debug(DEBUG_ACX, "acx set rx filter idx: %d enable: %d filter: %p", index, enable, filter); if (enable) { fields_size = wl1271_rx_filter_get_fields_size(filter); wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", filter->action, filter->num_fields, fields_size); } acx_size = ALIGN(sizeof(*acx) + fields_size, 4); acx = kzalloc(acx_size, GFP_KERNEL); if (!acx) return -ENOMEM; acx->enable = enable; acx->index = index; if (enable) { acx->num_fields = filter->num_fields; acx->action = filter->action; wl1271_rx_filter_flatten_fields(filter, acx->fields); } wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size); if (ret < 0) { wl1271_warning("setting rx filter failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation) { struct wl1271_acx_ht_capabilities *acx; u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* Allow HT Operation ? */ if (allow_ht_operation) { ht_capabilites = WL1271_ACX_FW_CAP_HT_OPERATION; if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) ht_capabilites |= WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) ht_capabilites |= WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) ht_capabilites |= WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; /* get data from A-MPDU parameters field */ acx->ampdu_max_length = ht_cap->ampdu_factor; acx->ampdu_min_spacing = ht_cap->ampdu_density; } memcpy(acx->mac_address, mac_address, ETH_ALEN); acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) { int ret; wl1271_debug(DEBUG_ACX, "acx statistics"); ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, sizeof(*stats)); if (ret < 0) { wl1271_warning("acx statistics failed: %d", ret); return -ENOMEM; } return 0; }
static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) { int buf_len, ret, len; struct sk_buff *skb; void *buf; u8 answer = 0; wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); if (!tb[WL1271_TM_ATTR_DATA]) return -EINVAL; buf = nla_data(tb[WL1271_TM_ATTR_DATA]); buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); if (tb[WL1271_TM_ATTR_ANSWER]) answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); if (buf_len > sizeof(struct wl1271_command)) return -EMSGSIZE; mutex_lock(&wl->mutex); ret = wl1271_cmd_test(wl, buf, buf_len, answer); mutex_unlock(&wl->mutex); if (ret < 0) { wl1271_warning("testmode cmd test failed: %d", ret); return ret; } if (answer) { len = nla_total_size(buf_len); skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); if (!skb) return -ENOMEM; NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); ret = cfg80211_testmode_reply(skb); if (ret < 0) return ret; } return 0; nla_put_failure: kfree_skb(skb); return -EMSGSIZE; }
/* * this command is basically the same as wl1271_acx_ht_capabilities, * with the addition of supported rates. they should be unified in * the next fw api change */ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, u32 rate_set, u8 hlid) { struct wlcore_acx_peer_cap *acx; int ret = 0; u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x", ht_cap->ht_supported, ht_cap->cap, rate_set); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } if (allow_ht_operation && ht_cap->ht_supported) { /* no need to translate capabilities - use the spec values */ ht_capabilites = ht_cap->cap; /* * this bit is not employed by the spec but only by FW to * indicate peer HT support */ ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; /* get data from A-MPDU parameters field */ acx->ampdu_max_length = ht_cap->ampdu_factor; acx->ampdu_min_spacing = ht_cap->ampdu_density; } acx->hlid = hlid; acx->ht_capabilites = cpu_to_le32(ht_capabilites); acx->supported_rates = cpu_to_le32(rate_set); ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool enable) { struct wl1271_acx_ps_rx_streaming *rx_streaming; u32 conf_queues, enable_queues; int i, ret = 0; wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); if (!rx_streaming) { ret = -ENOMEM; goto out; } conf_queues = wl->conf.rx_streaming.queues; if (enable) enable_queues = conf_queues; else enable_queues = 0; for (i = 0; i < 8; i++) { /* * Skip non-changed queues, to avoid redundant acxs. * this check assumes conf.rx_streaming.queues can't * be changed while rx_streaming is enabled. */ if (!(conf_queues & BIT(i))) continue; rx_streaming->role_id = wlvif->role_id; rx_streaming->tid = i; rx_streaming->enable = enable_queues & BIT(i); rx_streaming->period = wl->conf.rx_streaming.interval; rx_streaming->timeout = wl->conf.rx_streaming.interval; ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, rx_streaming, sizeof(*rx_streaming)); if (ret < 0) { wl1271_warning("acx ps rx streaming failed: %d", ret); goto out; } } out: kfree(rx_streaming); return ret; }
static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, u8 beacon) { memset(status, 0, sizeof(struct ieee80211_rx_status)); if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) status->band = IEEE80211_BAND_2GHZ; else status->band = IEEE80211_BAND_5GHZ; status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band); /* 11n support */ if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; status->signal = desc->rssi; /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we * need to divide by two for now, but TI has been discussing about * changing it. This needs to be rechecked. */ wl->noise = desc->rssi - (desc->snr >> 1); status->freq = ieee80211_channel_to_frequency(desc->channel, status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) { status->flag |= RX_FLAG_MMIC_ERROR; wl1271_warning("Michael MIC error. Desc: 0x%x", desc_err_code); } } if (beacon) wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, status->band); }
int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; struct wl1271_ini_general_params *gp = &((struct wl1271_nvs_file *)wl->nvs)->general_params; bool answer = false; int ret; if (!wl->nvs) return -ENODEV; gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; memcpy(&gen_parms->general_params, gp, sizeof(*gp)); if (gp->tx_bip_fem_auto_detect) answer = true; /* Override the REF CLK from the NVS with the one from platform data */ gen_parms->general_params.ref_clock = wl->ref_clock; /* LPD mode enable (bits 6-7) in WL1271 AP mode only */ if (wl->quirks & WL12XX_QUIRK_LPD_MODE) gen_parms->general_params.general_settings |= GENERAL_SETTINGS_DRPW_LPD; ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); goto out; } gp->tx_bip_fem_manufacturer = gen_parms->general_params.tx_bip_fem_manufacturer; wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); out: kfree(gen_parms); return ret; }
int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { struct acx_sta_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; int idx = 0; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } /* configure one basic rate class */ idx = ACX_TX_BASIC_RATE; acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); acx->rate_class[idx].short_retry_limit = c->short_retry_limit; acx->rate_class[idx].long_retry_limit = c->long_retry_limit; acx->rate_class[idx].aflags = c->aflags; /* configure one AP supported rate class */ idx = ACX_TX_AP_FULL_RATE; acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); acx->rate_class[idx].short_retry_limit = c->short_retry_limit; acx->rate_class[idx].long_retry_limit = c->long_retry_limit; acx->rate_class[idx].aflags = c->aflags; acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates, acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of rate policies failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl128x_cmd_radio_parms(struct wl1271 *wl) { struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; struct wl128x_radio_parms_cmd *radio_parms; struct wl128x_ini_general_params *gp = &nvs->general_params; int ret, fem_idx; if (!wl->nvs) return -ENODEV; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) return -ENOMEM; radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); /* 2.4GHz parameters */ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl128x_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, &nvs->dyn_radio_params_2[fem_idx].params, sizeof(struct wl128x_ini_fem_params_2)); /* 5GHz parameters */ memcpy(&radio_parms->static_params_5, &nvs->stat_radio_params_5, sizeof(struct wl128x_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, &nvs->dyn_radio_params_5[fem_idx].params, sizeof(struct wl128x_ini_fem_params_5)); radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", radio_parms, sizeof(*radio_parms)); ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); if (ret < 0) wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); kfree(radio_parms); return ret; }
static void wl1271_parse_fw_ver(struct wl1271 *wl) { int ret; ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], &wl->chip.fw_ver[4]); if (ret != 5) { wl1271_warning("fw version incorrect value"); memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); return; } /* Check if any quirks are needed with older fw versions */ wl->quirks |= wl12xx_get_fw_ver_quirks(wl); }
int wl1271_acx_ap_conn_estab_complete(struct wl1271 *wl) { struct acx_header_only_cfg *acx; int ret; wl1271_debug(DEBUG_ACX, "Sending AP Connection Establishment complete indication"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; ret = wl1271_cmd_configure(wl, ACX_AP_CONN_ESTAB_COMPLETE, acx, sizeof(*acx)); if (ret < 0) wl1271_warning("failed to send Connection Establishment complete indication: %d", ret); kfree(acx); return ret; }
int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, u16 template_id, void *buf, size_t buf_len, int index, u32 rates) { struct wl1271_cmd_template_set *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", template_id, role_id); WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } /* during initialization wlvif is NULL */ cmd->role_id = role_id; cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; cmd->enabled_rates = cpu_to_le32(rates); cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; cmd->index = index; if (buf) memcpy(cmd->template_data, buf, buf_len); ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_template failed: %d", ret); goto out_free; } out_free: kfree(cmd); out: return ret; }
/** * send test command to firmware * * @wl: wl struct * @buf: buffer containing the command, with all headers, must work with dma * @len: length of the buffer * @answer: is answer needed */ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) { int ret; size_t res_len = 0; wl1271_debug(DEBUG_CMD, "cmd test"); if (answer) res_len = buf_len; ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); if (ret < 0) { wl1271_warning("TEST command failed"); return ret; } return ret; }
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) { int ret; struct wl1271_command *cmd; struct sk_buff *skb; u8 ie_id; wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); if (!tb[WL1271_TM_ATTR_IE_ID]) return -EINVAL; ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return -ENOMEM; mutex_lock(&wl->mutex); ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); mutex_unlock(&wl->mutex); if (ret < 0) { wl1271_warning("testmode cmd interrogate failed: %d", ret); kfree(cmd); return ret; } skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); if (!skb) { kfree(cmd); return -ENOMEM; } NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); return 0; nla_put_failure: kfree_skb(skb); return -EMSGSIZE; }
static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, u8 beacon) { memset(status, 0, sizeof(struct ieee80211_rx_status)); if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) status->band = IEEE80211_BAND_2GHZ; else status->band = IEEE80211_BAND_5GHZ; status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); /* */ if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) status->flag |= RX_FLAG_HT; status->signal = desc->rssi; /* */ wl->noise = desc->rssi - (desc->snr >> 1); status->freq = ieee80211_channel_to_frequency(desc->channel, status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | RX_FLAG_DECRYPTED; if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { status->flag |= RX_FLAG_MMIC_ERROR; wl1271_warning("Michael MIC error"); } } }
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_ap_config_memory *mem_conf; struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); if (!mem_conf) { ret = -ENOMEM; goto out; } if (wl->chip.id == CHIP_ID_1283_PG20) /* * FIXME: The 128x AP FW does not yet support dynamic memory. * Use the base memory configuration for 128x for now. This * should be fine tuned in the future. */ mem = &wl->conf.mem_wl128x; else mem = &wl->conf.mem_wl127x; /* memory config */ mem_conf->num_stations = mem->num_stations; mem_conf->rx_mem_block_num = mem->rx_block_num; mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); if (ret < 0) { wl1271_warning("wl1271 mem config failed: %d", ret); goto out; } out: kfree(mem_conf); return ret; }
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, u8 hlid) { struct wl1271_acx_ht_capabilities *acx; int ret = 0; u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " "sta supp: %d sta cap: %d", ht_cap->ht_supported, ht_cap->cap); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { ret = -ENOMEM; goto out; } if (allow_ht_operation && ht_cap->ht_supported) { ht_capabilites = ht_cap->cap; ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; acx->ampdu_max_length = ht_cap->ampdu_factor; acx->ampdu_min_spacing = ht_cap->ampdu_density; } acx->hlid = hlid; acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); goto out; } out: kfree(acx); return ret; }
int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_sta_config_memory *mem_conf; struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); if (!mem_conf) { ret = -ENOMEM; goto out; } if (wl->chip.id == CHIP_ID_1283_PG20) mem = &wl->conf.mem_wl128x; else mem = &wl->conf.mem_wl127x; /* memory config */ mem_conf->num_stations = mem->num_stations; mem_conf->rx_mem_block_num = mem->rx_block_num; mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); mem_conf->dyn_mem_enable = mem->dynamic_memory; mem_conf->tx_free_req = mem->min_req_tx_blocks; mem_conf->rx_free_req = mem->min_req_rx_blocks; mem_conf->tx_min = mem->tx_min; mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); if (ret < 0) { wl1271_warning("wl1271 mem config failed: %d", ret); goto out; } out: kfree(mem_conf); return ret; }