int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_start *cmd; struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u32 supported_rates; int ret; wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); /* trying to use hidden SSID with an old hostapd version */ if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { wl1271_error("got a null SSID from beacon/bss"); ret = -EINVAL; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); if (ret < 0) goto out_free; ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); if (ret < 0) goto out_free_global; cmd->role_id = wlvif->role_id; cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->ap.bss_index = WL1271_AP_BSS_INDEX; cmd->ap.global_hlid = wlvif->ap.global_hlid; cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; cmd->ap.global_session_id = wl->session_ids[wlvif->ap.global_hlid]; cmd->ap.bcast_session_id = wl->session_ids[wlvif->ap.bcast_hlid]; cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; /* FIXME: Change when adding DFS */ cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ cmd->ap.wmm = wlvif->wmm_enabled; cmd->channel = wlvif->channel; cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); if (!bss_conf->hidden_ssid) { /* take the SSID from the beacon for backward compatibility */ cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; cmd->ap.ssid_len = wlvif->ssid_len; memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); } else { cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; cmd->ap.ssid_len = bss_conf->ssid_len; memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); } supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); if (wlvif->p2p) supported_rates &= ~CONF_TX_CCK_RATES; wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x", supported_rates); cmd->ap.local_rates = cpu_to_le32(supported_rates); switch (wlvif->band) { case IEEE80211_BAND_2GHZ: cmd->band = WLCORE_BAND_2_4GHZ; break; case IEEE80211_BAND_5GHZ: cmd->band = WLCORE_BAND_5GHZ; break; default: wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); cmd->band = WLCORE_BAND_2_4GHZ; break; } ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role start ap"); goto out_free_bcast; } goto out_free; out_free_bcast: wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); out_free_global: wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); out_free: kfree(cmd); out: return ret; }
int wlcore_rx(struct wl1271 *wl, struct wl_fw_status *status) { unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0}; u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc; u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc; u32 rx_counter; u32 pkt_len, align_pkt_len; u32 pkt_offset, des; u8 hlid; enum wl_rx_buf_align rx_align; int ret = 0; int orig_cnt = wl->rx_counter, diff; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; rx_counter = drv_rx_counter; while (rx_counter != fw_rx_counter) { des = le32_to_cpu(status->rx_pkt_descs[rx_counter]); pkt_len = wlcore_rx_get_buf_size(wl, des); align_pkt_len = wlcore_rx_get_align_buf_size(wl, pkt_len); if (buf_size + align_pkt_len > wl->aggr_buf_size) break; buf_size += align_pkt_len; rx_counter++; rx_counter %= wl->num_rx_desc; } if (buf_size == 0) { wl1271_warning("received empty data"); break; } /* Read all available packets at once */ des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); ret = wlcore_hw_prepare_read(wl, des, buf_size); if (ret < 0) goto out; ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, buf_size, true); if (ret < 0) goto out; /* Split data into separate packets */ pkt_offset = 0; while (pkt_offset < buf_size) { des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); pkt_len = wlcore_rx_get_buf_size(wl, des); rx_align = wlcore_hw_get_rx_buf_align(wl, des); /* * the handle data call can only fail in memory-outage * conditions, in that case the received frame will just * be dropped. */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, pkt_len, rx_align, &hlid) == 1) { if (hlid < wl->num_links) __set_bit(hlid, active_hlids); else WARN(1, "hlid (%d) exceeded MAX_LINKS\n", hlid); } wl->rx_counter++; drv_rx_counter++; drv_rx_counter %= wl->num_rx_desc; pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len); } } /* * Write the driver's packet counter to the FW. This is only required * for older hardware revisions */ if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, wl->rx_counter); if (ret < 0) goto out; } wl12xx_rearm_rx_streaming(wl, active_hlids); diff = wl->rx_counter - orig_cnt; if (diff > 32) { wl1271_error("invalid Rx completed packets %d\n", diff); } else { wl->rx_completions[diff-1]++; } out: return ret; }
int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; u32 supported_rates; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); cmd->role_id = wlvif->role_id; if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WLCORE_BAND_5GHZ; cmd->channel = wlvif->channel; cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; cmd->sta.ssid_len = wlvif->ssid_len; memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); if (wlvif->p2p) supported_rates &= ~CONF_TX_CCK_RATES; cmd->sta.local_rates = cpu_to_le32(supported_rates); cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type); if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); if (ret) goto out_free; } cmd->sta.hlid = wlvif->sta.hlid; cmd->sta.session = wl->session_ids[wlvif->sta.hlid]; /* * We don't have the correct remote rates in this stage. The * rates will be reconfigured later, after association, if the * firmware supports ACX_PEER_CAP. Otherwise, there's nothing * we can do, so use all supported_rates here. */ cmd->sta.remote_rates = cpu_to_le32(supported_rates); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", wlvif->role_id, cmd->sta.hlid, cmd->sta.session, wlvif->basic_rate_set, wlvif->rate_set); ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role start sta"); goto err_hlid; } wlvif->sta.role_chan_type = wlvif->channel_type; goto out_free; err_hlid: /* clear links on error. */ wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); out: return ret; }
void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret = 0; enum nl80211_band band; u32 rate, mask; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: band = NL80211_BAND_2GHZ; mask = wlvif->bitrate_masks[band]; if (wl->scan.req->no_cck) { mask &= ~CONF_TX_CCK_RATES; if (!mask) mask = CONF_TX_RATE_MASK_BASIC_P2P; } rate = wl1271_tx_min_rate_get(wl, mask); ret = wl1271_scan_send(wl, wlvif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: band = NL80211_BAND_2GHZ; mask = wlvif->bitrate_masks[band]; if (wl->scan.req->no_cck) { mask &= ~CONF_TX_CCK_RATES; if (!mask) mask = CONF_TX_RATE_MASK_BASIC_P2P; } rate = wl1271_tx_min_rate_get(wl, mask); ret = wl1271_scan_send(wl, wlvif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: band = NL80211_BAND_5GHZ; rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); ret = wl1271_scan_send(wl, wlvif, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: band = NL80211_BAND_5GHZ; rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); ret = wl1271_scan_send(wl, wlvif, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl, wlvif); } break; case WL1271_SCAN_STATE_DONE: wl->scan.failed = false; cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); break; default: wl1271_error("invalid scan state"); break; } if (ret < 0) { cancel_delayed_work(&wl->scan_complete_work); ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, msecs_to_jiffies(0)); } }
static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum nl80211_band band, bool passive, u32 basic_rate) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl1271_cmd_scan *cmd; struct wl1271_cmd_trigger_scan_to *trigger; int ret; u16 scan_options = 0; /* skip active scans if we don't have SSIDs */ if (!passive && wl->scan.req->n_ssids == 0) return WL1271_NOTHING_TO_SCAN; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { ret = -ENOMEM; goto out; } if (wl->conf.scan.split_scan_timeout) scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; /* scan on the dev role if the regular one is not started */ if (wlcore_is_p2p_mgmt(wlvif)) cmd->params.role_id = wlvif->dev_role_id; else cmd->params.role_id = wlvif->role_id; if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, cmd->channels, band, passive); if (cmd->params.n_ch == 0) { ret = WL1271_NOTHING_TO_SCAN; goto out; } cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; if (band == NL80211_BAND_2GHZ) cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; else cmd->params.band = WL1271_SCAN_BAND_5_GHZ; if (wl->scan.ssid_len) { cmd->params.ssid_len = wl->scan.ssid_len; memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } memcpy(cmd->addr, vif->addr, ETH_ALEN); ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->params.role_id, band, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len, NULL, 0, false); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; } trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, sizeof(*trigger), 0); if (ret < 0) { wl1271_error("trigger scan to failed for hw scan"); goto out; } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd); kfree(trigger); return ret; }
int wl1271_ps_elp_wakeup(struct wl1271 *wl) { DECLARE_COMPLETION_ONSTACK(compl); unsigned long flags; int ret; u32 start_time = jiffies; bool pending = false; /* we might try to wakeup although we didn't go to sleep (e.g. on boot) */ if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) return 0; /* don't cancel_sync as it might contend for a mutex and deadlock */ cancel_delayed_work(&wl->elp_work); if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; wl1271_debug(DEBUG_PSM, "waking up chip from elp"); /* * The spinlock is required here to synchronize both the work and * the completion variable in one entity. */ spin_lock_irqsave(&wl->wl_lock, flags); if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) pending = true; else wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); if (!pending) { ret = wait_for_completion_timeout( &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_error("ELP wakeup timeout!"); ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -ETIMEDOUT; goto err; } else if (ret < 0) { wl1271_error("ELP wakeup completion error."); goto err; } } clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", jiffies_to_msecs(jiffies - start_time)); goto out; err: spin_lock_irqsave(&wl->wl_lock, flags); wl->elp_compl = NULL; spin_unlock_irqrestore(&wl->wl_lock, flags); return ret; out: return 0; }
static int wl1271_boot_run_firmware(struct wl1271 *wl) { int loop, ret; u32 chip_id, interrupt; wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); chip_id = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); if (chip_id != wl->chip.id) { wl1271_error("chip id doesn't match after firmware boot"); return -EIO; } /* wait for init to complete */ loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); interrupt = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); if (interrupt == 0xffffffff) { wl1271_error("error reading hardware complete " "init indication"); return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_INIT_COMPLETE); break; } } if (loop > INIT_LOOP) { wl1271_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; } /* get hardware config command mail box */ wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR); /* get hardware config event mail box */ wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); wl1271_boot_fw_version(wl); /* * in case of full asynchronous mode the firmware event must be * ready to receive event from the command mailbox */ /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | SCAN_COMPLETE_EVENT_ID | PS_REPORT_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); return ret; } wl1271_event_mbox_config(wl); /* firmware startup completed */ return 0; }
static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_scan_request *req) { struct wl18xx_cmd_scan_params *cmd; struct wlcore_scan_channels *cmd_channels = NULL; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->role_id = wlvif->role_id; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->scan_type = SCAN_TYPE_SEARCH; cmd->rssi_threshold = -127; cmd->snr_threshold = 0; cmd->bss_type = SCAN_BSS_TYPE_ANY; cmd->ssid_from_list = 0; cmd->filter = 0; cmd->add_broadcast = 0; cmd->urgency = 0; cmd->protect = 0; cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->terminate_after = 0; /* configure channels */ WARN_ON(req->n_ssids > 1); cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); if (!cmd_channels) { ret = -ENOMEM; goto out; } wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_SEARCH); wl18xx_adjust_channels(cmd, cmd_channels); /* * all the cycles params (except total cycles) should * remain 0 for normal scan */ cmd->total_cycles = 1; if (req->no_cck) cmd->rate = WL18XX_SCAN_RATE_6; cmd->tag = WL1271_SCAN_DEFAULT_TAG; if (req->n_ssids) { cmd->ssid_len = req->ssids[0].ssid_len; memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); } /* TODO: per-band ies? */ if (cmd->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, NULL, 0, false); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (cmd->active[1] || cmd->dfs) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, NULL, 0, false); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd_channels); kfree(cmd); return ret; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, bool unaligned, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; u16 seq_num; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->state == WL1271_STATE_PLT)) return -EINVAL; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* discard corrupted packets */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: case WL1271_RX_DESC_DECRYPT_FAIL: wl1271_warning("corrupted packet in RX with status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; case WL1271_RX_DESC_SUCCESS: case WL1271_RX_DESC_MIC_FAIL: break; default: wl1271_error("invalid RX descriptor status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } /* skb length not included rx descriptor */ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, length - sizeof(*desc)); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_trim(skb, skb->len - desc->pad_len); if (wl->log_wakes > 0) { print_hex_dump(KERN_INFO, DRIVER_PREFIX "wake: ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, min_t(size_t, skb->len, 96), true); --wl->log_wakes; } skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
static int wl1271_chip_wakeup(struct wl1271 *wl) { int ret = 0; wl1271_power_on(wl); msleep(WL1271_POWER_ON_SLEEP); wl1271_spi_reset(wl); wl1271_spi_init(wl); /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ wl1271_set_partition(wl, 0x00000000, 0x00000000, REGISTERS_BASE, REGISTERS_DOWN_SIZE); /* ELP module wake up */ wl1271_fw_wakeup(wl); /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ switch (wl->chip.id) { case CHIP_ID_1271_PG10: wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", wl->chip.id); ret = wl1271_setup(wl); if (ret < 0) goto out; break; case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); ret = wl1271_setup(wl); if (ret < 0) goto out; break; default: wl1271_error("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; goto out; } if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) goto out; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { ret = wl1271_fetch_nvs(wl); if (ret < 0) goto out; } out: return ret; }
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf) { struct wl1271 *wl = hw->priv; const u8 *addr; int ret; u8 key_type; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); addr = sta ? sta->addr : bcast_addr; wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", key_conf->alg, key_conf->keyidx, key_conf->keylen, key_conf->flags); wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); if (is_zero_ether_addr(addr)) { /* We dont support TX only encryption */ ret = -EOPNOTSUPP; goto out; } mutex_lock(&wl->mutex); ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out_unlock; switch (key_conf->alg) { case ALG_WEP: key_type = KEY_WEP; key_conf->hw_key_idx = key_conf->keyidx; break; case ALG_TKIP: key_type = KEY_TKIP; key_conf->hw_key_idx = key_conf->keyidx; break; case ALG_CCMP: key_type = KEY_AES; key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; default: wl1271_error("Unknown key algo 0x%x", key_conf->alg); ret = -EOPNOTSUPP; goto out_sleep; } switch (cmd) { case SET_KEY: ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, addr); if (ret < 0) { wl1271_error("Could not add or replace key"); goto out_sleep; } break; case DISABLE_KEY: ret = wl1271_cmd_set_key(wl, KEY_REMOVE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, addr); if (ret < 0) { wl1271_error("Could not remove key"); goto out_sleep; } break; default: wl1271_error("Unsupported key cmd 0x%x", cmd); ret = -EOPNOTSUPP; goto out_sleep; break; } out_sleep: wl1271_ps_elp_sleep(wl); out_unlock: mutex_unlock(&wl->mutex); out: return ret; }
static int __devinit wl1271_probe(struct spi_device *spi) { struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; int ret, i; static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; pdata = spi->dev.platform_data; if (!pdata) { wl1271_error("no platform data"); return -ENODEV; } hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { wl1271_error("could not alloc ieee80211_hw"); return -ENOMEM; } wl = hw->priv; memset(wl, 0, sizeof(*wl)); wl->hw = hw; dev_set_drvdata(&spi->dev, wl); wl->spi = spi; skb_queue_head_init(&wl->tx_queue); INIT_WORK(&wl->filter_work, wl1271_filter_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; wl->listen_int = 1; wl->rx_counter = 0; wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; wl->elp = false; wl->psm = 0; wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; /* We use the default power on sleep time until we know which chip * we're using */ for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; spin_lock_init(&wl->wl_lock); /* * In case our MAC address is not correctly set, * we use a random but Nokia MAC. */ memcpy(wl->mac_addr, nokia_oui, 3); get_random_bytes(wl->mac_addr + 3, 3); wl->state = WL1271_STATE_OFF; mutex_init(&wl->mutex); wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); if (!wl->rx_descriptor) { wl1271_error("could not allocate memory for rx descriptor"); ret = -ENOMEM; goto out_free; } /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; ret = spi_setup(spi); if (ret < 0) { wl1271_error("spi_setup failed"); goto out_free; } wl->set_power = pdata->set_power; if (!wl->set_power) { wl1271_error("set power function missing in platform data"); ret = -ENODEV; goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { wl1271_error("irq missing in platform data"); ret = -ENODEV; goto out_free; } ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); ret = platform_device_register(&wl1271_device); if (ret) { wl1271_error("couldn't register platform device"); goto out_irq; } dev_set_drvdata(&wl1271_device.dev, wl); ret = wl1271_init_ieee80211(wl); if (ret) goto out_platform; ret = wl1271_register_hw(wl); if (ret) goto out_platform; wl1271_debugfs_init(wl); wl1271_notice("initialized"); return 0; out_platform: platform_device_unregister(&wl1271_device); out_irq: free_irq(wl->irq, wl); out_free: kfree(wl->rx_descriptor); wl->rx_descriptor = NULL; ieee80211_free_hw(hw); return ret; }
static int wl1271_boot_run_firmware(struct wl1271 *wl) { int loop, ret; u32 chip_id, intr; ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); if (ret < 0) goto out; ret = wl1271_read32(wl, CHIP_ID_B, &chip_id); if (ret < 0) goto out; wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); if (chip_id != wl->chip.id) { wl1271_error("chip id doesn't match after firmware boot"); ret = -EIO; goto out; } /* wait for init to complete */ loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); ret = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) goto out; if (intr == 0xffffffff) { wl1271_error("error reading hardware complete " "init indication"); ret = -EIO; goto out; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { ret = wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_INIT_COMPLETE); if (ret < 0) goto out; break; } } if (loop > INIT_LOOP) { wl1271_error("timeout waiting for the hardware to " "complete initialization"); ret = -EIO; goto out; } /* get hardware config command mail box */ ret = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr); if (ret < 0) goto out; /* get hardware config event mail box */ ret = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR, &wl->event_box_addr); if (ret < 0) goto out; /* set the working partition to its "running" mode offset */ ret = wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); if (ret < 0) goto out; wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); ret = wl1271_boot_fw_version(wl); if (ret < 0) goto out; /* * in case of full asynchronous mode the firmware event must be * ready to receive event from the command mailbox */ /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | SCAN_COMPLETE_EVENT_ID | ROLE_STOP_COMPLETE_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID | DUMMY_PACKET_EVENT_ID | PEER_REMOVE_COMPLETE_EVENT_ID | BA_SESSION_RX_CONSTRAINT_EVENT_ID | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | INACTIVE_STA_EVENT_ID | MAX_TX_RETRY_EVENT_ID | CHANNEL_SWITCH_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); goto out; } ret = wl1271_event_mbox_config(wl); /* firmware startup completed */ out: return ret; }
static int wl1271_boot_upload_nvs(struct wl1271 *wl) { size_t nvs_len, burst_len; int i; u32 dest_addr, val; u8 *nvs_ptr, *nvs_aligned; int ret; if (wl->nvs == NULL) return -ENODEV; if (wl->chip.id == CHIP_ID_1283_PG20) { struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { if (nvs->general_params.dual_mode_select) wl->enable_11a = true; } else { wl1271_error("nvs size is not as expected: %zu != %zu", wl->nvs_len, sizeof(struct wl128x_nvs_file)); kfree(wl->nvs); wl->nvs = NULL; wl->nvs_len = 0; return -EILSEQ; } /* only the first part of the NVS needs to be uploaded */ nvs_len = sizeof(nvs->nvs); nvs_ptr = (u8 *)nvs->nvs; } else { struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; /* * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz * band configurations) can be removed when those NVS files stop * floating around. */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { if (nvs->general_params.dual_mode_select) wl->enable_11a = true; } if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || wl->enable_11a)) { wl1271_error("nvs size is not as expected: %zu != %zu", wl->nvs_len, sizeof(struct wl1271_nvs_file)); kfree(wl->nvs); wl->nvs = NULL; wl->nvs_len = 0; return -EILSEQ; } /* only the first part of the NVS needs to be uploaded */ nvs_len = sizeof(nvs->nvs); nvs_ptr = (u8 *) nvs->nvs; } /* update current MAC address to NVS */ nvs_ptr[11] = wl->addresses[0].addr[0]; nvs_ptr[10] = wl->addresses[0].addr[1]; nvs_ptr[6] = wl->addresses[0].addr[2]; nvs_ptr[5] = wl->addresses[0].addr[3]; nvs_ptr[4] = wl->addresses[0].addr[4]; nvs_ptr[3] = wl->addresses[0].addr[5]; /* * Layout before the actual NVS tables: * 1 byte : burst length. * 2 bytes: destination address. * n bytes: data to burst copy. * * This is ended by a 0 length, then the NVS tables. */ /* FIXME: Do we need to check here whether the LSB is 1? */ while (nvs_ptr[0]) { burst_len = nvs_ptr[0]; dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); /* * Due to our new wl1271_translate_reg_addr function, * we need to add the REGISTER_BASE to the destination */ dest_addr += REGISTERS_BASE; /* We move our pointer to the data */ nvs_ptr += 3; for (i = 0; i < burst_len; i++) { if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) goto out_badnvs; val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); wl1271_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); ret = wl1271_write32(wl, dest_addr, val); if (ret < 0) return ret; nvs_ptr += 4; dest_addr += 4; } if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) goto out_badnvs; } /* * We've reached the first zero length, the first NVS table * is located at an aligned offset which is at least 7 bytes further. * NOTE: The wl->nvs->nvs element must be first, in order to * simplify the casting, we assume it is at the beginning of * the wl->nvs structure. */ nvs_ptr = (u8 *)wl->nvs + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) goto out_badnvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ ret = wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); if (ret < 0) return ret; /* Copy the NVS tables to a new block to ensure alignment */ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); if (!nvs_aligned) return -ENOMEM; /* And finally we upload the NVS tables */ ret = wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); if (ret < 0) return ret; kfree(nvs_aligned); return 0; out_badnvs: wl1271_error("nvs data is malformed"); return -EILSEQ; }
/* Returns the scan type to be used or a negative value on error */ static int wl12xx_scan_set_ssid_list(struct wl1271 *wl, struct cfg80211_sched_scan_request *req) { struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; struct cfg80211_match_set *sets = req->match_sets; struct cfg80211_ssid *ssids = req->ssids; int ret = 0, type, i, j, n_match_ssids = 0; wl1271_debug(DEBUG_CMD, "cmd scan ssid list"); /* count the match sets that contain SSIDs */ for (i = 0; i < req->n_match_sets; i++) if (sets[i].ssid.ssid_len > 0) n_match_ssids++; /* No filter, no ssids or only bcast ssid */ if (!n_match_ssids && (!req->n_ssids || (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { type = SCAN_SSID_FILTER_ANY; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } if (!n_match_ssids) { /* No filter, with ssids */ type = SCAN_SSID_FILTER_DISABLED; for (i = 0; i < req->n_ssids; i++) { cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, ssids[i].ssid_len); cmd->n_ssids++; } } else { type = SCAN_SSID_FILTER_LIST; /* Add all SSIDs from the filters */ for (i = 0; i < req->n_match_sets; i++) { /* ignore sets without SSIDs */ if (!sets[i].ssid.ssid_len) continue; cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; memcpy(cmd->ssids[cmd->n_ssids].ssid, sets[i].ssid.ssid, sets[i].ssid.ssid_len); cmd->n_ssids++; } if ((req->n_ssids > 1) || (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { /* * Mark all the SSIDs passed in the SSID list as HIDDEN, * so they're used in probe requests. */ for (i = 0; i < req->n_ssids; i++) { if (!req->ssids[i].ssid_len) continue; for (j = 0; j < cmd->n_ssids; j++) if ((req->ssids[i].ssid_len == cmd->ssids[j].len) && !memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, req->ssids[i].ssid_len)) { cmd->ssids[j].type = SCAN_SSID_TYPE_HIDDEN; break; } /* Fail if SSID isn't present in the filters */ if (j == cmd->n_ssids) { ret = -EINVAL; goto out_free; } } } } wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("cmd sched scan ssid list failed"); goto out_free; } out_free: kfree(cmd); out: if (ret < 0) return ret; return type; }
static int __devinit wl1271_probe(struct spi_device *spi) { struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; unsigned long irqflags; int ret; pdata = spi->dev.platform_data; if (!pdata) { wl1271_error("no platform data"); return -ENODEV; } hw = wl1271_alloc_hw(); if (IS_ERR(hw)) return PTR_ERR(hw); wl = hw->priv; dev_set_drvdata(&spi->dev, wl); wl->if_priv = spi; wl->if_ops = &spi_ops; /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; ret = spi_setup(spi); if (ret < 0) { wl1271_error("spi_setup failed"); goto out_free; } wl->set_power = pdata->set_power; if (!wl->set_power) { wl1271_error("set power function missing in platform data"); ret = -ENODEV; goto out_free; } wl->ref_clock = pdata->board_ref_clock; wl->tcxo_clock = pdata->board_tcxo_clock; wl->platform_quirks = pdata->platform_quirks; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) irqflags = IRQF_TRIGGER_RISING; #else if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) irqflags = IRQF_TRIGGER_RISING; else irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; #endif wl->irq = spi->irq; if (wl->irq < 0) { wl1271_error("irq missing in platform data"); ret = -ENODEV; goto out_free; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) ret = compat_request_threaded_irq(&wl->irq_compat, wl->irq, wl1271_hardirq, wl1271_irq, irqflags, DRIVER_NAME, wl); #else ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, irqflags, DRIVER_NAME, wl); #endif if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; ret = wl1271_register_hw(wl); if (ret) goto out_irq; wl1271_notice("initialized"); return 0; out_irq: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) compat_free_threaded_irq(&wl->irq_compat); #else free_irq(wl->irq, wl); #endif out_free: wl1271_free_hw(wl); return ret; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271_cmd_scan_params *cmd; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int ret; int filter_type; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); if (req->n_short_intervals > SCAN_MAX_SHORT_INTERVALS) { wl1271_warning("Number of short intervals requested (%d)" "exceeds limit (%d)", req->n_short_intervals, SCAN_MAX_SHORT_INTERVALS); return -EINVAL; } filter_type = wl12xx_scan_set_ssid_list(wl,req); if (filter_type < 0) return filter_type; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } cmd->role_id = wlvif->role_id; /* report APs when at least 1 is found */ //cfg->report_after = 1; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->scan_type = SCAN_TYPE_PERIODIC; cmd->rssi_threshold = c->rssi_threshold; cmd->snr_threshold = c->snr_threshold; /* don't filter on BSS type */ cmd->bss_type = SCAN_BSS_TYPE_ANY; cmd->ssid_from_list = 1; if (filter_type == SCAN_SSID_FILTER_LIST) cmd->filter = 1; cmd->add_broadcast = 0; /* TODO: figure this ones out */ cmd->urgency = 0; cmd->protect = 0; cmd->n_probe_reqs = c->num_probe_reqs; /* don't stop scanning automatically when something is found */ cmd->terminate_after = 0; /* configure channels */ wlcore_set_scan_chan_params(wl, cmd, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_PERIODIC); /* TODO: check params */ cmd->short_cycles_sec = req->short_interval; cmd->long_cycles_sec = req->long_interval; cmd->short_cycles_count = req->n_short_intervals; cmd->total_cycles = 0; /* TODO: how to set tx rate? */ cmd->tag = WL1271_SCAN_DEFAULT_TAG; /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ cmd->report_threshold = 1; cmd->terminate_on_report = 0; if (cmd->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, ies->ie[band], ies->len[band], true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (cmd->active[1] || cmd->dfs) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, ies->ie[band], ies->len[band], true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); wl1271_info("scan size: %d", sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd); return ret; }
/* * send command to firmware * * @wl: wl struct * @id: command id * @buf: buffer containing the command, must work with dma * @len: length of the buffer */ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret = 0; u16 status; u16 poll_count = 0; if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING))) return -EIO; cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); ret = wl1271_write(wl, wl->cmd_box_addr, buf, len, false); if (ret < 0) goto fail; ret = wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); if (ret < 0) goto fail; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) goto fail; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); ret = -ETIMEDOUT; goto fail; } poll_count++; if (poll_count < WL1271_CMD_FAST_POLL_COUNT) udelay(10); else msleep(1); ret = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) goto fail; } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); ret = wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); if (ret < 0) goto fail; status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); ret = -EIO; goto fail; } ret = wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); return ret; fail: wl12xx_queue_recovery_work(wl); return ret; }
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, size_t fw_data_len, u32 dest) { struct wl1271_partition_set partition; int addr, chunk_num, partition_limit; u8 *p, *chunk; /* whal_FwCtrl_LoadFwImageSm() */ wl1271_debug(DEBUG_BOOT, "starting firmware upload"); wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", fw_data_len, CHUNK_SIZE); if ((fw_data_len % 4) != 0) { wl1271_error("firmware length not multiple of four"); return -EIO; } chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); if (!chunk) { wl1271_error("allocation for firmware upload chunk failed"); return -ENOMEM; } memcpy(&partition, &part_table[PART_DOWN], sizeof(partition)); partition.mem.start = dest; wl1271_set_partition(wl, &partition); /* 10.1 set partition limit and chunk num */ chunk_num = 0; partition_limit = part_table[PART_DOWN].mem.size; while (chunk_num < fw_data_len / CHUNK_SIZE) { /* 10.2 update partition, if needed */ addr = dest + (chunk_num + 2) * CHUNK_SIZE; if (addr > partition_limit) { addr = dest + chunk_num * CHUNK_SIZE; partition_limit = chunk_num * CHUNK_SIZE + part_table[PART_DOWN].mem.size; partition.mem.start = addr; wl1271_set_partition(wl, &partition); } /* 10.3 upload the chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; memcpy(chunk, p, CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false); chunk_num++; } /* 10.4 upload the last chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; memcpy(chunk, p, fw_data_len % CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); kfree(chunk); return 0; }
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_start *cmd; struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; int ret; wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); /* trying to use a non-hidden SSID without SSID IE */ if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { wl1271_error("got a null SSID from beacon/bss"); ret = -EINVAL; goto out; } /* trying to use hidden SSID without configured SSID */ if (bss_conf->ssid_len == 0 && bss_conf->hidden_ssid) { wl1271_error("missing hidden SSID"); ret = -EINVAL; goto out; } cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); if (ret < 0) goto out_free; ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); if (ret < 0) goto out_free_global; cmd->role_id = wlvif->role_id; cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->ap.bss_index = WL1271_AP_BSS_INDEX; cmd->ap.global_hlid = wlvif->ap.global_hlid; cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ap.dtim_interval = bss_conf->dtim_period; cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; /* FIXME: Change when adding DFS */ cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ cmd->channel = wlvif->channel; if (!bss_conf->hidden_ssid) { /* take the SSID from the beacon for backward compatibility */ cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; cmd->ap.ssid_len = wlvif->ssid_len; memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); } else { cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; cmd->ap.ssid_len = bss_conf->ssid_len; memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); } cmd->ap.local_rates = cpu_to_le32(0xffffffff); switch (wlvif->band) { case IEEE80211_BAND_2GHZ: cmd->band = RADIO_BAND_2_4GHZ; break; case IEEE80211_BAND_5GHZ: cmd->band = RADIO_BAND_5GHZ; break; default: wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); cmd->band = RADIO_BAND_2_4GHZ; break; } ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role start ap"); goto out_free_bcast; } goto out_free; out_free_bcast: wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); out_free_global: wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); out_free: kfree(cmd); out: return ret; }
static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; int ret; /* We are only able to handle the wlan function */ if (func->num != 0x02) return -ENODEV; hw = wl1271_alloc_hw(); if (IS_ERR(hw)) return PTR_ERR(hw); wl = hw->priv; wl->if_priv = func; wl->if_ops = &sdio_ops; /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); wl1271_error("missing wlan platform data: %d", ret); goto out_free; } wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; ret = wl1271_register_hw(wl); if (ret) goto out_irq; sdio_set_drvdata(func, wl); /* Tell PM core that we don't need the card to be powered now */ pm_runtime_put_noidle(&func->dev); wl1271_notice("initialized"); return 0; out_irq: free_irq(wl->irq, wl); out_free: wl1271_free_hw(wl); return ret; }
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct wl12xx_cmd_role_start *cmd; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); cmd->role_id = wlvif->role_id; if (wlvif->band == IEEE80211_BAND_5GHZ) cmd->band = WL12XX_BAND_5GHZ; cmd->channel = wlvif->channel; cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); cmd->ibss.dtim_interval = bss_conf->dtim_period; cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; cmd->ibss.ssid_len = wlvif->ssid_len; memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); if (ret) goto out_free; } cmd->ibss.hlid = wlvif->sta.hlid; cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " "basic_rate_set: 0x%x, remote_rates: 0x%x", wlvif->role_id, cmd->sta.hlid, cmd->sta.session, wlvif->basic_rate_set, wlvif->rate_set); wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", vif->bss_conf.bssid); ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to initiate cmd role enable"); goto err_hlid; } goto out_free; err_hlid: /* clear links on error. */ wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: kfree(cmd); out: return ret; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct wlcore_scan_channels *cfg_channels = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->role_id = wlvif->role_id; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; /* cycles set to 0 it means infinite (until manually stopped) */ cfg->cycles = 0; /* report APs when at least 1 is found */ cfg->report_after = 1; /* don't stop scanning automatically when something is found */ cfg->terminate = 0; cfg->tag = WL1271_SCAN_DEFAULT_TAG; /* don't filter on BSS type */ cfg->bss_type = SCAN_BSS_TYPE_ANY; /* currently NL80211 supports only a single interval */ for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->scan_plans[0].interval * MSEC_PER_SEC); cfg->ssid_len = 0; ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); if (ret < 0) goto out; cfg->filter_type = ret; wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL); if (!cfg_channels) { ret = -ENOMEM; goto out; } if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_PERIODIC)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; } wl12xx_adjust_channels(cfg, cfg_channels); if (!force_passive && cfg->active[0]) { u8 band = NL80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ies[band], ies->len[band], ies->common_ies, ies->common_ie_len, true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (!force_passive && cfg->active[1]) { u8 band = NL80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ies[band], ies->len[band], ies->common_ies, ies->common_ie_len, true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, sizeof(*cfg), 0); if (ret < 0) { wl1271_error("SCAN configuration failed"); goto out; } out: kfree(cfg_channels); kfree(cfg); return ret; }
static int __devinit wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; unsigned long irqflags; int ret; /* We are only able to handle the wlan function */ if (func->num != 0x02) return -ENODEV; hw = wl1271_alloc_hw(); if (IS_ERR(hw)) return PTR_ERR(hw); wl = hw->priv; wl->if_priv = func; wl->if_ops = &sdio_ops; /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); wl1271_error("missing wlan platform data: %d", ret); goto out_free; } wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; wl->tcxo_clock = wlan_data->board_tcxo_clock; wl->platform_quirks = wlan_data->platform_quirks; if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) irqflags = IRQF_TRIGGER_RISING; else irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free; } disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; ret = wl1271_register_hw(wl); if (ret) goto out_irq; sdio_set_drvdata(func, wl); /* Tell PM core that we don't need the card to be powered now */ pm_runtime_put_noidle(&func->dev); wl1271_notice("initialized"); return 0; out_irq: free_irq(wl->irq, wl); out_free: wl1271_free_hw(wl); return ret; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, enum wl_rx_buf_align rx_align, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; u16 seq_num; u32 pkt_data_len; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->plt)) return -EINVAL; pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length); if (!pkt_data_len) { wl1271_error("Invalid packet arrived from HW. length %d", length); return -EINVAL; } if (rx_align == WLCORE_RX_BUF_UNALIGNED) reserved = RX_BUF_ALIGN; else if (rx_align == WLCORE_RX_BUF_PADDED) offset_to_data = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } /* discard corrupted packets */ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { hdr = (void *)(data + sizeof(*desc) + offset_to_data); wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", desc->status & WL1271_RX_DESC_STATUS_MASK, pkt_data_len); wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), min(pkt_data_len, ieee80211_hdrlen(hdr->frame_control))); return -EINVAL; } /* skb length not including rx descriptor */ skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, pkt_data_len); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wlcore_hw_set_rx_csum(wl, desc, skb); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); if (req->n_short_intervals > SCAN_MAX_SHORT_INTERVALS) { wl1271_warning("Number of short intervals requested (%d)" "exceeds limit (%d)", req->n_short_intervals, SCAN_MAX_SHORT_INTERVALS); return -EINVAL; } cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return -ENOMEM; cfg->role_id = wlvif->dev_role_id; cfg->rssi_threshold = c->rssi_threshold; cfg->snr_threshold = c->snr_threshold; cfg->n_probe_reqs = c->num_probe_reqs; /* cycles set to 0 it means infinite (until manually stopped) */ cfg->cycles = 0; /* report APs when at least 1 is found */ cfg->report_after = 1; /* don't stop scanning automatically when something is found */ cfg->terminate = 0; cfg->tag = WL1271_SCAN_DEFAULT_TAG; /* don't filter on BSS type */ cfg->bss_type = SCAN_BSS_TYPE_ANY; for (i = 1; i < SCAN_MAX_CYCLE_INTERVALS; i++) { if (i <= req->n_short_intervals) cfg->intervals[i] = cpu_to_le32(req->short_interval); else cfg->intervals[i] = cpu_to_le32(req->long_interval); } cfg->ssid_len = 0; ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req); if (ret < 0) goto out; cfg->filter_type = ret; wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; } if (!force_passive && cfg->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->dev_role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], ies->len[band], true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (!force_passive && cfg->active[1]) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, wlvif->dev_role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], ies->len[band], true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, sizeof(*cfg), 0); if (ret < 0) { wl1271_error("SCAN configuration failed"); goto out; } out: kfree(cfg); return ret; }
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret, extra = 0; u16 fc; struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; struct wl12xx_arp_rsp_template *tmpl; struct ieee80211_hdr_3addr *hdr; struct arphdr *arp_hdr; skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + WL1271_EXTRA_SPACE_MAX); if (!skb) { wl1271_error("failed to allocate buffer for arp rsp template"); return -ENOMEM; } skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); memset(tmpl, 0, sizeof(*tmpl)); /* llc layer */ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); tmpl->llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl->arp_hdr; arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); tmpl->sender_ip = wlvif->ip_addr; /* encryption space */ switch (wlvif->encryption_type) { case KEY_TKIP: if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) extra = WL1271_EXTRA_SPACE_TKIP; break; case KEY_AES: extra = WL1271_EXTRA_SPACE_AES; break; case KEY_NONE: case KEY_WEP: case KEY_GEM: extra = 0; break; default: wl1271_warning("Unknown encryption type: %d", wlvif->encryption_type); ret = -EINVAL; goto out; } if (extra) { u8 *space = skb_push(skb, extra); memset(space, 0, extra); } /* QoS header - BE */ if (wlvif->sta.qos) memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); /* mac80211 header */ hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; if (wlvif->sta.qos) fc |= IEEE80211_STYPE_QOS_DATA; else fc |= IEEE80211_STYPE_DATA; if (wlvif->encryption_type != KEY_NONE) fc |= IEEE80211_FCTL_PROTECTED; hdr->frame_control = cpu_to_le16(fc); memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); memcpy(hdr->addr2, vif->addr, ETH_ALEN); memset(hdr->addr3, 0xff, ETH_ALEN); ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, skb->data, skb->len, 0, wlvif->basic_rate); out: dev_kfree_skb(skb); return ret; }
static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl1271_cmd_scan_params *cmd; int ret; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } /* TODO: delete split_scan_timeout conf */ /* scan on the dev role if the regular one is not started */ if (wlvif->role_id == WL12XX_INVALID_ROLE_ID) cmd->role_id = wlvif->dev_role_id; else cmd->role_id = wlvif->role_id; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; goto out; } cmd->scan_type = SCAN_TYPE_SEARCH; cmd->rssi_threshold = -127; cmd->snr_threshold = 0; /* TODO: use wlvif->type instead? */ cmd->bss_type = SCAN_BSS_TYPE_ANY; cmd->ssid_from_list = 0; cmd->filter = 0; cmd->add_broadcast = 0; /* TODO: figure this ones out */ cmd->urgency = 0; cmd->protect = 0; /* TODO: take num_probe from req if available */ cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->terminate_after = 0; /* configure channels */ WARN_ON(req->n_ssids > 1); /* TODO: support multi ssid */ wlcore_set_scan_chan_params(wl, cmd, req->channels, req->n_channels, req->n_ssids, SCAN_TYPE_SEARCH); /* * all the cycles params (except total cycles) should * remain 0 for normal scan */ cmd->total_cycles = 1; if (req->no_cck) cmd->rate = WLCORE_SCAN_RATE_6; cmd->tag = WL1271_SCAN_DEFAULT_TAG; if (req->n_ssids) { cmd->ssid_len = req->ssids[0].ssid_len; memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); } /* TODO: per-band ies? */ if (cmd->active[0]) { u8 band = IEEE80211_BAND_2GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, false); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; } } if (cmd->active[1] || cmd->dfs) { u8 band = IEEE80211_BAND_5GHZ; ret = wl12xx_cmd_build_probe_req(wl, wlvif, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, false); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; } } wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("SCAN failed"); goto out; } out: kfree(cmd); return ret; }
/* * send command to firmware * * @wl: wl struct * @id: command id * @buf: buffer containing the command, must work with dma * @len: length of the buffer * return the cmd status code on success. */ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret; u16 status; u16 poll_count = 0; if (unlikely(wl->state == WLCORE_STATE_RESTARTING && id != CMD_STOP_FWLOGGER)) return -EIO; if (WARN_ON_ONCE(len < sizeof(*cmd))) return -EIO; cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); if (ret < 0) return ret; /* * TODO: we just need this because one bit is in a different * place. Is there any better way? */ ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); if (ret < 0) return ret; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); return -ETIMEDOUT; } poll_count++; if (poll_count < WL1271_CMD_FAST_POLL_COUNT) udelay(10); else msleep(1); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); if (ret < 0) return ret; status = le16_to_cpu(cmd->status); ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); if (ret < 0) return ret; return status; }
int wl18xx_process_mailbox_events(struct wl1271 *wl) { struct wl18xx_event_mailbox *mbox = wl->mbox; u32 vector; vector = le32_to_cpu(mbox->events_vector); wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "scan results: %d", mbox->number_of_scan_results); if (wl->scan_wlvif) wl18xx_scan_completed(wl, wl->scan_wlvif); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT (results %d)", mbox->number_of_sched_scan_results); wlcore_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) wlcore_event_sched_scan_completed(wl, 1); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) wlcore_event_ba_rx_constraint(wl, le16_to_cpu(mbox->rx_ba_role_id_bitmap), le16_to_cpu(mbox->rx_ba_allowed_bitmap)); if (vector & BSS_LOSS_EVENT_ID) wlcore_event_beacon_loss(wl, le16_to_cpu(mbox->bss_loss_bitmap)); if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) wlcore_event_channel_switch(wl, le16_to_cpu(mbox->channel_switch_role_id_bitmap), true); if (vector & DUMMY_PACKET_EVENT_ID) wlcore_event_dummy_packet(wl); /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. */ if (vector & MAX_TX_FAILURE_EVENT_ID) wlcore_event_max_tx_failure(wl, le32_to_cpu(mbox->tx_retry_exceeded_bitmap)); if (vector & INACTIVE_STA_EVENT_ID) wlcore_event_inactive_sta(wl, le32_to_cpu(mbox->inactive_sta_bitmap)); if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) wlcore_event_roc_complete(wl); if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) { struct wl12xx_vif *wlvif; struct ieee80211_vif *vif; u8 role_id = mbox->rx_ba_role_id; u8 link_id = mbox->rx_ba_link_id; u8 win_size = mbox->rx_ba_win_size; int prev_win_size; wl1271_debug(DEBUG_EVENT, "%s. role_id=%u link_id=%u win_size=%u", "RX_BA_WIN_SIZE_CHANGE_EVENT_ID", role_id, link_id, win_size); wlvif = wl->links[link_id].wlvif; if (unlikely(!wlvif)) { wl1271_error("%s. link_id wlvif is null", "RX_BA_WIN_SIZE_CHANGE_EVENT_ID"); goto out_event; } if (unlikely(wlvif->role_id != role_id)) { wl1271_error("%s. wlvif has different role_id=%d", "RX_BA_WIN_SIZE_CHANGE_EVENT_ID", wlvif->role_id); goto out_event; } prev_win_size = wlcore_rx_ba_max_subframes(wl, link_id); if (unlikely(prev_win_size < 0)) { wl1271_error("%s. cannot get link rx_ba_max_subframes", "RX_BA_WIN_SIZE_CHANGE_EVENT_ID"); goto out_event; } if ((u8) prev_win_size <= win_size) { /* This not supposed to happen unless a FW bug */ wl1271_error("%s. prev_win_size(%d) <= win_size(%d)", "RX_BA_WIN_SIZE_CHANGE_EVENT_ID", prev_win_size, win_size); goto out_event; } /* * Call MAC routine to update win_size and stop all link active * BA sessions. This routine returns 0 on failure or previous * win_size on success */ vif = wl12xx_wlvif_to_vif(wlvif); ieee80211_change_rx_ba_max_subframes(vif, (wlvif->bss_type != BSS_TYPE_AP_BSS ? vif->bss_conf.bssid : wl->links[link_id].addr), win_size); } if (vector & SMART_CONFIG_SYNC_EVENT_ID) wlcore_smart_config_sync_event(wl, mbox->sc_sync_channel, mbox->sc_sync_band); if (vector & SMART_CONFIG_DECODE_EVENT_ID) wlcore_smart_config_decode_event(wl, mbox->sc_ssid_len, mbox->sc_ssid, mbox->sc_pwd_len, mbox->sc_pwd); out_event: return 0; }