void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) { struct ieee80211_tx_info *info; struct sk_buff *skb; unsigned long flags; spin_lock_irqsave(&wcn->dxe_lock, flags); skb = wcn->tx_ack_skb; wcn->tx_ack_skb = NULL; spin_unlock_irqrestore(&wcn->dxe_lock, flags); if (!skb) { wcn36xx_warn("Spurious TX complete indication\n"); return; } info = IEEE80211_SKB_CB(skb); if (status == 1) info->flags |= IEEE80211_TX_STAT_ACK; wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status); ieee80211_tx_status_irqsafe(wcn->hw, skb); ieee80211_wake_queues(wcn->hw); }
static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_config_bss_rsp_msg *rsp; struct wcn36xx_hal_config_bss_rsp_params *params; if (len < sizeof(*rsp)) return -EINVAL; rsp = (struct wcn36xx_hal_config_bss_rsp_msg *)buf; params = &rsp->bss_rsp_params; if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { wcn36xx_warn("hal config bss response failure: %d", params->status); return -EIO; } wcn36xx_dbg(WCN36XX_DBG_HAL, "hal config bss rsp status %d bss_idx %d dpu_desc_index %d" " sta_idx %d self_idx %d bcast_idx %d mac %pM power %d", params->status, params->bss_index, params->dpu_desc_index, params->bss_sta_index, params->bss_self_sta_index, params->bss_bcast_sta_idx, params->mac, params->tx_mgmt_power); wcn->current_vif->sta_index = params->bss_sta_index; wcn->current_vif->dpu_desc_index = params->dpu_desc_index; return 0; }
int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, struct sk_buff *skb) { struct wcn36xx_hal_send_probe_resp_req_msg msg; INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ); /* // TODO need to find out why this is needed? */ /* msg_body.beacon_length = skb_beacon->len + 6; */ if (skb->len > BEACON_TEMPLATE_SIZE) { wcn36xx_warn("probe response template is too big: %d", skb->len); return -E2BIG; } msg.probe_resp_template_len = skb->len; memcpy(&msg.probe_resp_template, skb->data, skb->len); memcpy(&msg.bssid, &wcn->addresses[0], ETH_ALEN); PREPARE_HAL_BUF(wcn->smd_buf, msg); wcn36xx_dbg(WCN36XX_DBG_HAL, "hal update probe rsp len %d bssid %pM", msg.probe_resp_template_len, msg.bssid); return wcn36xx_smd_send_and_wait(wcn, msg.header.len); };
static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_config_sta_rsp_msg *rsp; struct config_sta_rsp_params *params; if (len < sizeof(*rsp)) return -EINVAL; rsp = (struct wcn36xx_hal_config_sta_rsp_msg *)buf; params = &rsp->params; if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { wcn36xx_warn("hal config sta response failure: %d", params->status); return -EIO; } wcn36xx_dbg(WCN36XX_DBG_HAL, "hal config sta rsp status %d sta_index %d bssid_index %d p2p %d", params->status, params->sta_index, params->bssid_index, params->p2p); return 0; }
void wcn36xx_rx_ready_work(struct work_struct *work) { struct wcn36xx *wcn = container_of(work, struct wcn36xx, rx_ready_work); int int_src; wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); /* RX_LOW_PRI */ if (int_src & WCN36XX_DXE_INT_CH1_MASK) { wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_INT_CH1_MASK); wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch)); } /* RX_HIGH_PRI */ if (int_src & WCN36XX_DXE_INT_CH3_MASK) { /* Clean up all the INT within this channel */ wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_INT_CH3_MASK); wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch)); } if (!int_src) wcn36xx_warn("No DXE interrupt pending"); enable_irq(wcn->rx_irq); }
static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_add_sta_self_rsp_msg *rsp; if (len < sizeof(*rsp)) return -EINVAL; rsp = (struct wcn36xx_hal_add_sta_self_rsp_msg *)buf; if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) { wcn36xx_warn("hal add sta self failure: %d", rsp->status); return -EIO; } wcn36xx_dbg(WCN36XX_DBG_HAL, "hal add sta self status %d " "self_sta_index %d dpu_index %d", rsp->status, rsp->self_sta_index, rsp->dpu_index); wcn->current_vif->sta_index = rsp->self_sta_index; wcn->current_vif->dpu_desc_index = rsp->dpu_index; return 0; }
static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) { struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl; struct wcn36xx_dxe_desc *dxe = ctl->desc; dma_addr_t dma_addr; struct sk_buff *skb; while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; wcn36xx_dxe_fill_skb(ctl); switch (ch->ch_type) { case WCN36XX_DXE_CH_RX_L: dxe->ctrl = WCN36XX_DXE_CTRL_RX_L; break; case WCN36XX_DXE_CH_RX_H: dxe->ctrl = WCN36XX_DXE_CTRL_RX_H; break; default: wcn36xx_warn("Unknown channel"); } dma_unmap_single(NULL, dma_addr, WCN36XX_PKT_SIZE, DMA_FROM_DEVICE); wcn36xx_rx_skb(wcn, skb); ctl = ctl->next; dxe = ctl->desc; } ch->head_blk_ctl = ctl; return 0; }
void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn) { int int_src; wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); /* RX_LOW_PRI */ if (int_src & WCN36XX_DXE_INT_CH1_MASK) wcn36xx_rx_handle_packets(wcn, &wcn->dxe_rx_l_ch, WCN36XX_DXE_CTRL_RX_L, WCN36XX_DXE_INT_CH1_MASK, WCN36XX_INT_MASK_CHAN_RX_L, WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_L); /* RX_HIGH_PRI */ if (int_src & WCN36XX_DXE_INT_CH3_MASK) wcn36xx_rx_handle_packets(wcn, &wcn->dxe_rx_h_ch, WCN36XX_DXE_CTRL_RX_H, WCN36XX_DXE_INT_CH3_MASK, WCN36XX_INT_MASK_CHAN_RX_H, WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_H); if (!int_src) wcn36xx_warn("No DXE interrupt pending\n"); }
static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_msg_header *msg_header = buf; wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len); switch (msg_header->msg_type) { case WCN36XX_HAL_START_RSP: wcn36xx_smd_start_rsp(wcn, buf, len); break; case WCN36XX_HAL_CONFIG_STA_RSP: wcn36xx_smd_config_sta_rsp(wcn, buf, len); break; case WCN36XX_HAL_CONFIG_BSS_RSP: wcn36xx_smd_config_bss_rsp(wcn, buf, len); break; case WCN36XX_HAL_STOP_RSP: case WCN36XX_HAL_ADD_STA_SELF_RSP: wcn36xx_smd_add_sta_self_rsp(wcn, buf, len); break; case WCN36XX_HAL_DEL_STA_SELF_RSP: case WCN36XX_HAL_DELETE_STA_RSP: case WCN36XX_HAL_INIT_SCAN_RSP: case WCN36XX_HAL_START_SCAN_RSP: case WCN36XX_HAL_END_SCAN_RSP: case WCN36XX_HAL_FINISH_SCAN_RSP: case WCN36XX_HAL_DOWNLOAD_NV_RSP: case WCN36XX_HAL_DELETE_BSS_RSP: case WCN36XX_HAL_SEND_BEACON_RSP: case WCN36XX_HAL_SET_LINK_ST_RSP: case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP: case WCN36XX_HAL_SET_BSSKEY_RSP: case WCN36XX_HAL_SET_STAKEY_RSP: if (wcn36xx_smd_rsp_status_check(buf, len)) { wcn36xx_warn("error response from hal request %d", msg_header->msg_type); } break; case WCN36XX_HAL_JOIN_RSP: wcn36xx_smd_join_rsp(buf, len); break; case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: wcn36xx_smd_update_scan_params_rsp(buf, len); break; case WCN36XX_HAL_CH_SWITCH_RSP: wcn36xx_smd_switch_channel_rsp(buf, len); break; case WCN36XX_HAL_OTA_TX_COMPL_IND: wcn36xx_smd_tx_compl_ind(wcn, buf, len); break; default: wcn36xx_error("SMD_EVENT (%d) not supported", msg_header->msg_type); } }
void wcn36xx_fill_tx_bd(struct wcn36xx *wcn, struct wcn36xx_tx_bd *bd, u8 broadcast, u8 encrypt, struct ieee80211_hdr *hdr, bool tx_compl) { bd->dpu_rf = WCN36XX_BMU_WQ_TX; bd->pdu.tid = WCN36XX_TID; bd->pdu.reserved3 = 0xd; if (broadcast) { /* broadcast */ bd->ub = 1; bd->queue_id = WCN36XX_TX_B_WQ_ID; /* default rate for broadcast */ if (ieee80211_is_mgmt(hdr->frame_control)) bd->bd_rate = (wcn->band == IEEE80211_BAND_5GHZ) ? WCN36XX_BD_RATE_CTRL : WCN36XX_BD_RATE_MGMT; /* No ack needed not unicast */ bd->ack_policy = 1; } else { bd->queue_id = WCN36XX_TX_U_WQ_ID; /* default rate for unicast */ bd->ack_policy = 0; if (ieee80211_is_data(hdr->frame_control)) bd->bd_rate = WCN36XX_BD_RATE_DATA; else if (ieee80211_is_mgmt(hdr->frame_control)) bd->bd_rate = (wcn->band == IEEE80211_BAND_5GHZ) ? WCN36XX_BD_RATE_CTRL : WCN36XX_BD_RATE_MGMT; else if (ieee80211_is_ctl(hdr->frame_control)) bd->bd_rate = WCN36XX_BD_RATE_CTRL; else wcn36xx_warn("frame control type unknown"); } if (ieee80211_is_data(hdr->frame_control)) { bd->dpu_sign = wcn->current_vif->ucast_dpu_signature; bd->queue_id = 0; bd->sta_index = wcn->current_vif->sta_index; bd->dpu_desc_idx = wcn->current_vif->dpu_desc_index; } else { bd->sta_index = wcn->current_vif->self_sta_index; bd->dpu_desc_idx = wcn->current_vif->self_dpu_desc_index; } bd->dpu_ne = encrypt; bd->tx_comp = tx_compl; buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); bd->tx_bd_sign = 0xbdbdbdbd; }
static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len) { struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf; if (len != sizeof(*rsp)) { wcn36xx_warn("Bad TX complete indication"); return -EIO; } wcn36xx_dxe_tx_ack_ind(wcn, rsp->status); return 0; }
static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) { struct wcn36xx_hal_update_scan_params_resp *rsp; rsp = (struct wcn36xx_hal_update_scan_params_resp *)buf; /* Remove the PNO version bit */ rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK)); if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) { wcn36xx_warn("error response from update scan"); return -EIO; } return 0; }
void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn) { int int_src; wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); /* RX_LOW_PRI */ if (int_src & WCN36XX_DXE_INT_CH1_MASK) { wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_INT_CH1_MASK); wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch)); } /* RX_HIGH_PRI */ if (int_src & WCN36XX_DXE_INT_CH3_MASK) { /* Clean up all the INT within this channel */ wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_INT_CH3_MASK); wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch)); } if (!int_src) wcn36xx_warn("No DXE interrupt pending\n"); }
int wcn36xx_smd_config_bss(struct wcn36xx *wcn, enum nl80211_iftype type, const u8 *bssid, bool update, u16 beacon_interval) { struct wcn36xx_hal_config_bss_req_msg msg; struct wcn36xx_hal_config_bss_params *bss; struct wcn36xx_hal_config_sta_params *sta; INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_BSS_REQ); bss = &msg.bss_params; sta = &bss->sta; WARN_ON(is_zero_ether_addr(bssid)); memcpy(&bss->bssid, bssid, ETH_ALEN); memcpy(&bss->self_mac_addr, &wcn->addresses[0], ETH_ALEN); if (type == NL80211_IFTYPE_STATION) { bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE; /* STA */ bss->oper_mode = 1; } else if (type == NL80211_IFTYPE_AP) { bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE; /* AP */ bss->oper_mode = 0; } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_MESH_POINT) { bss->bss_type = WCN36XX_HAL_IBSS_MODE; /* STA */ bss->oper_mode = 1; } else { wcn36xx_warn("Unknown type for bss config: %d", type); } bss->nw_type = WCN36XX_HAL_11G_NW_TYPE; bss->short_slot_time_supported = 0; bss->lla_coexist = 0; bss->llb_coexist = 0; bss->llg_coexist = 0; bss->ht20_coexist = 0; bss->lln_non_gf_coexist = 0; bss->lsig_tx_op_protection_full_support = 0; bss->rifs_mode = 0; bss->beacon_interval = beacon_interval; bss->dtim_period = 2; bss->tx_channel_width_set = 0; bss->oper_channel = wcn->ch; bss->ext_channel = 0; bss->reserved = 0; memcpy(&sta->bssid, bssid, ETH_ALEN); sta->aid = wcn->aid; sta->type = 0; sta->short_preamble_supported = 0; memcpy(&sta->mac, &wcn->addresses[0], ETH_ALEN); sta->listen_interval = 8; sta->wmm_enabled = 0; sta->ht_capable = 0; sta->tx_channel_width_set = 0; sta->rifs_mode = 0; sta->lsig_txop_protection = 0; sta->max_ampdu_size = 0; sta->max_ampdu_density = 0; sta->sgi_40mhz = 0; sta->sgi_20Mhz = 0; memcpy(&sta->supported_rates, &wcn->supported_rates, sizeof(wcn->supported_rates)); sta->rmf = 0; sta->encrypt_type = 0; sta->action = 0; sta->uapsd = 0; sta->max_sp_len = 0; sta->green_field_capable = 0; sta->mimo_ps = 0; sta->delayed_ba_support = 0; sta->max_ampdu_duration = 0; sta->dsss_cck_mode_40mhz = 0; sta->sta_index = 0xff; sta->bssid_index = 0; sta->p2p = 0; /* wcn->ssid is only valid in AP and IBSS mode */ bss->ssid.length = wcn->ssid.length; memcpy(bss->ssid.ssid, wcn->ssid.ssid, wcn->ssid.length); bss->action = 0; /* FIXME: set rateset */ bss->ht = 0; bss->obss_prot_enabled = 0; bss->rmf = 0; bss->ht_oper_mode = 0; bss->dual_cts_protection = 0; bss->max_probe_resp_retry_limit = 0; bss->hidden_ssid = 0; bss->proxy_probe_resp = 0; bss->edca_params_valid = 0; /* FIXME: set acbe, acbk, acvi and acvo */ bss->ext_set_sta_key_param_valid = 0; /* FIXME: set ext_set_sta_key_param */ bss->wcn36xx_hal_persona = 1; bss->spectrum_mgt_enable = 0; bss->tx_mgmt_power = 0; bss->max_tx_power = 0x10; if (update) { sta->bssid_index = 0; bss->action = 1; } else { sta->bssid_index = 0xff; bss->action = 0; } if (!(wcn->fw_major == 1 && wcn->fw_minor == 2 && wcn->fw_version == 2 && wcn->fw_revision == 24)) return wcn36xx_smd_config_bss_v1(wcn, &msg); PREPARE_HAL_BUF(wcn->smd_buf, msg); wcn36xx_dbg(WCN36XX_DBG_HAL, "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d", bss->bssid, bss->self_mac_addr, bss->bss_type, bss->oper_mode, bss->nw_type); wcn36xx_dbg(WCN36XX_DBG_HAL, "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM", sta->bssid, sta->action, sta->sta_index, sta->bssid_index, sta->aid, sta->type, sta->mac); return wcn36xx_smd_send_and_wait(wcn, msg.header.len); }
static int wcn36xx_start(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; int ret; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start"); /* SMD initialization */ ret = wcn36xx_smd_open(wcn); if (ret) { wcn36xx_error("Failed to open smd channel: %d", ret); goto out_err; } /* Not to receive INT until the whole buf from SMD is read */ smd_disable_read_intr(wcn->smd_ch); /* Allocate memory pools for Mgmt BD headers and Data BD headers */ ret = wcn36xx_dxe_allocate_mem_pools(wcn); if (ret) { wcn36xx_error("Failed to alloc DXE mempool: %d", ret); goto out_smd_close; } wcn36xx_dxe_alloc_ctl_blks(wcn); if (ret) { wcn36xx_error("Failed to alloc DXE ctl blocks: %d", ret); goto out_free_dxe_pool; } INIT_WORK(&wcn->rx_ready_work, wcn36xx_rx_ready_work); /* Maximum SMD message size is 4k */ wcn->smd_buf = kmalloc(4096, GFP_KERNEL); if (!wcn->smd_buf) { wcn36xx_error("Failed to allocate smd buf"); ret = -ENOMEM; goto out_free_dxe_ctl; } /* TODO pass configuration to FW */ ret = wcn36xx_smd_load_nv(wcn); if (ret) { wcn36xx_error("Failed to push NV to chip"); goto out_free_smd_buf; } ret = wcn36xx_smd_start(wcn); if (ret) { wcn36xx_error("Failed to start chip"); goto out_free_smd_buf; } /* DMA channel initialization */ ret = wcn36xx_dxe_init(wcn); if (ret) { wcn36xx_error("DXE init failed"); goto out_smd_stop; } wcn36xx_pmc_init(wcn); wcn36xx_debugfs_init(wcn); if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { ret = wcn36xx_smd_feature_caps_exchange(wcn); if (ret) wcn36xx_warn("Exchange feature caps failed"); } return 0; out_smd_stop: wcn36xx_smd_stop(wcn); out_free_smd_buf: kfree(wcn->smd_buf); out_free_dxe_pool: wcn36xx_dxe_free_mem_pools(wcn); out_free_dxe_ctl: wcn36xx_dxe_free_ctl_blks(wcn); out_smd_close: wcn36xx_smd_close(wcn); out_err: return ret; }