1bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi/* 2bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Intel Wireless Multicomm 3200 WiFi driver 3bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 4bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Copyright (C) 2009 Intel Corporation. All rights reserved. 5bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 6bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Redistribution and use in source and binary forms, with or without 7bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * modification, are permitted provided that the following conditions 8bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * are met: 9bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 10bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * * Redistributions of source code must retain the above copyright 11bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * notice, this list of conditions and the following disclaimer. 12bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * * Redistributions in binary form must reproduce the above copyright 13bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * notice, this list of conditions and the following disclaimer in 14bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * the documentation and/or other materials provided with the 15bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * distribution. 16bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * * Neither the name of Intel Corporation nor the names of its 17bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * contributors may be used to endorse or promote products derived 18bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * from this software without specific prior written permission. 19bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 20bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 32bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 33bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Intel Corporation <ilw@linux.intel.com> 34bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Samuel Ortiz <samuel.ortiz@intel.com> 35bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Zhu Yi <yi.zhu@intel.com> 36bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 37bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 38bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 39bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/kernel.h> 40bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/netdevice.h> 41d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 42bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/etherdevice.h> 43bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/wireless.h> 44bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/ieee80211.h> 45bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/if_arp.h> 46bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <linux/list.h> 475a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 48bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include <net/iw_handler.h> 49bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 50bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "iwm.h" 51bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "debug.h" 52bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "hal.h" 53bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "umac.h" 54bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "lmac.h" 55bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "commands.h" 56bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "rx.h" 57bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "cfg80211.h" 58bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#include "eeprom.h" 59bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 60bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) 61bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 62bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || 63bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) 64bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 65bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 66bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 67bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 68bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 69bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) 70bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 71bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), 72bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 16); 73bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 74bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 75bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi/* 76bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Notification handlers: 77bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 78bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * For every possible notification we can receive from the 79bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * target, we have a handler. 80bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * When we get a target notification, and there is no one 81bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * waiting for it, it's just processed through the rx code 82bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * path: 83bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 84bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * iwm_rx_handle() 85bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * -> iwm_rx_handle_umac() 86bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * -> iwm_rx_handle_wifi() 87bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * -> iwm_rx_handle_resp() 88bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * -> iwm_ntf_*() 89bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 90bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * OR 91bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 92bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * -> iwm_rx_handle_non_wifi() 93bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 94bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * If there are processes waiting for this notification, then 95bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * iwm_rx_handle_wifi() just wakes those processes up and they 96bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * grab the pending notification. 97bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 98bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, 99bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 100bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 101bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_error *error; 102bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_fw_error_hdr *fw_err; 103bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 104bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi error = (struct iwm_umac_notif_error *)buf; 105bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi fw_err = &error->err; 106bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 10704e715cd46ba523806070fbf9ded009f10e107cdSamuel Ortiz memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); 10804e715cd46ba523806070fbf9ded009f10e107cdSamuel Ortiz 109bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "%cMAC FW ERROR:\n", 110bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); 111bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); 112bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); 113bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); 114bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); 115bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); 116bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); 117bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); 118bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); 119bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); 120bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); 121bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); 122bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); 123bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); 124bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 125d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz iwm_resetting(iwm); 126d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz 127bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 128bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 129bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 130bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, 131bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 132bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 133bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_alive *alive_resp = 134bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_alive *)(buf); 135bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 status = le16_to_cpu(alive_resp->status); 136bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 137bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { 138bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); 139bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EIO; 140bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 141bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 142bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_tx_credit_init_pools(iwm, alive_resp); 143bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 144bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 145bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 146bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 147bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, 148bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 149bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 150bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 151257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 152bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_init_complete *init_complete = 153bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_init_complete *)(buf); 154bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 status = le16_to_cpu(init_complete->status); 155257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); 156bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 157257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi if (blocked) 158bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); 159257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi else 160bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); 161257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi 162257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi wiphy_rfkill_set_hw_state(wiphy, blocked); 163bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 164bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 165bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 166bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 167bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, 168bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 169bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 170bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 171bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int pool_nr, total_freed_pages; 172bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long pool_map; 173bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i, id; 174bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_page_dealloc *dealloc = 175bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_page_dealloc *)buf; 176bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 177bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); 178bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); 179bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 180bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " 181bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "update map 0x%lx\n", pool_nr, pool_map); 182bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 183bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi spin_lock(&iwm->tx_credit.lock); 184bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 185bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < pool_nr; i++) { 186bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi id = GET_VAL32(dealloc->grp_info[i], 187bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi UMAC_DEALLOC_NTFY_GROUP_NUM); 188bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (test_bit(id, &pool_map)) { 189bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi total_freed_pages = GET_VAL32(dealloc->grp_info[i], 190bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi UMAC_DEALLOC_NTFY_PAGE_CNT); 191bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_tx_credit_inc(iwm, id, total_freed_pages); 192bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 193bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 194bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 195bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi spin_unlock(&iwm->tx_credit.lock); 196bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 197bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 198bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 199bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 200bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, 201bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 202bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 203bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); 204bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 205bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 206bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 207bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 208bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, 209bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 210bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 211bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 212bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); 213bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 214bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 215bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 216bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 217bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, 218bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 219bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 220bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_lmac_tx_resp *tx_resp; 221bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_wifi_in_hdr *hdr; 222bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 223bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi tx_resp = (struct iwm_lmac_tx_resp *) 224bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 225bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct iwm_umac_wifi_in_hdr *)buf; 226bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 2274fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); 2284fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi 2294fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", 2304fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); 2314fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); 2324fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", 2334fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi le16_to_cpu(tx_resp->retry_cnt)); 2344fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); 2354fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", 2364fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi le16_to_cpu(tx_resp->byte_cnt)); 2374fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); 238bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 239bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 240bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 241bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 242bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 243bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, 244bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 245bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 246bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 opcode; 247bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 *calib_buf; 248bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) 249bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 250bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 251bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi opcode = hdr->opcode; 252bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 253bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi BUG_ON(opcode >= CALIBRATION_CMD_NUM || 254bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi opcode < PHY_CALIBRATE_OPCODES_NUM); 255bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 256bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", 257bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi opcode); 258bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 259bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); 260bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi calib_buf = iwm->calib_res[opcode].buf; 261bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 262bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { 263bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(calib_buf); 264bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi calib_buf = kzalloc(buf_size, GFP_KERNEL); 265bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!calib_buf) { 266bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); 267bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -ENOMEM; 268bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 269bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->calib_res[opcode].buf = calib_buf; 270bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->calib_res[opcode].size = buf_size; 271bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 272bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 273bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(calib_buf, hdr, buf_size); 274bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); 275bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 276bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 277bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 278bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 279bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, 280bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 281bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 282bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 283bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); 284bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 285bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 286bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 287bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 288bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, 289bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 290bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 291bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_lmac_cal_cfg_resp *cal_resp; 292bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 293bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cal_resp = (struct iwm_lmac_cal_cfg_resp *) 294bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 295bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 296bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", 297bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(cal_resp->status)); 298bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 299bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 300bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 301bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 302bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, 303bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 304bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 305bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_wifi_status *status = 306bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_wifi_status *)buf; 307bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 308bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->core_enabled |= le16_to_cpu(status->status); 309bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 310bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 311bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 312bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 313bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct iwm_rx_ticket_node * 314bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yiiwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) 315bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 316bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket_node; 317bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 318bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); 319bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!ticket_node) { 320bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate ticket node\n"); 321bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ERR_PTR(-ENOMEM); 322bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 323bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 324ff020726a7e963c3b9fb71825b3c33885022a8f0Julia Lawall ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket), 325ff020726a7e963c3b9fb71825b3c33885022a8f0Julia Lawall GFP_KERNEL); 326bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!ticket_node->ticket) { 327bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); 328bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(ticket_node); 329bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ERR_PTR(-ENOMEM); 330bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 331bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 332bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi INIT_LIST_HEAD(&ticket_node->node); 333bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 334bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ticket_node; 335bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 336bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 337bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) 338bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 339bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(ticket_node->ticket); 340bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(ticket_node); 341bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 342bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 343bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) 344bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 345bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 id_hash = IWM_RX_ID_GET_HASH(id); 34604d1c22761f33ac8f345665e7ef809c875142425Zhu Yi struct iwm_rx_packet *packet; 347bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 348c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->packet_lock[id_hash]); 34904d1c22761f33ac8f345665e7ef809c875142425Zhu Yi list_for_each_entry(packet, &iwm->rx_packets[id_hash], node) 350c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi if (packet->id == id) { 351c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi list_del(&packet->node); 352c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->packet_lock[id_hash]); 353bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return packet; 354c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi } 355bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 356c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->packet_lock[id_hash]); 357bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return NULL; 358bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 359bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 360bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, 361bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 size, u16 id) 362bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 363bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet; 364bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 365bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); 366bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!packet) { 367bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate packet\n"); 368bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ERR_PTR(-ENOMEM); 369bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 370bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 371bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet->skb = dev_alloc_skb(size); 372bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!packet->skb) { 373bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); 374bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(packet); 375bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ERR_PTR(-ENOMEM); 376bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 377bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 378bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet->pkt_size = size; 379bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 380bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb_put(packet->skb, size); 381bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(packet->skb->data, buf, size); 382bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi INIT_LIST_HEAD(&packet->node); 383bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet->id = id; 384bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 385bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return packet; 386bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 387bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 388bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yivoid iwm_rx_free(struct iwm_priv *iwm) 389bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 390bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket, *nt; 391bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet, *np; 392bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i; 393bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 394c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->ticket_lock); 395bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { 396bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_del(&ticket->node); 397bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_rx_ticket_node_free(ticket); 398bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 399c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->ticket_lock); 400bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 401bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < IWM_RX_ID_HASH; i++) { 402c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->packet_lock[i]); 403bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], 404bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi node) { 405bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_del(&packet->node); 406bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree_skb(packet->skb); 407bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(packet); 408bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 409c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->packet_lock[i]); 410bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 411bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 412bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 413bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, 414bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 415bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 416bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = 417bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_rx_ticket *)buf; 418bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket *ticket = 419bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; 420bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i, schedule_rx = 0; 421bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 422bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { 423bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket_node; 424bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 425bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (le16_to_cpu(ticket->action)) { 426bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_RX_TICKET_RELEASE: 427bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_RX_TICKET_DROP: 428bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* We can push the packet to the stack */ 429bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); 430bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (IS_ERR(ticket_node)) 431bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return PTR_ERR(ticket_node); 432bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 43369cf6e2d5bd90436a0fa6cef2f4d65583faef388Samuel Ortiz IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n", 4343c997e8849c5b982662f2a9b3e8cb64260382faaSamuel Ortiz __le16_to_cpu(ticket->action) == 4353c997e8849c5b982662f2a9b3e8cb64260382faaSamuel Ortiz IWM_RX_TICKET_RELEASE ? 43669cf6e2d5bd90436a0fa6cef2f4d65583faef388Samuel Ortiz "RELEASE" : "DROP", 4374fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi ticket->id); 438c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->ticket_lock); 439bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_add_tail(&ticket_node->node, &iwm->rx_tickets); 440c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->ticket_lock); 441bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 442bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* 443bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * We received an Rx ticket, most likely there's 444bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * a packet pending for it, it's not worth going 445bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * through the packet hash list to double check. 446bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Let's just fire the rx worker.. 447bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 448bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi schedule_rx = 1; 449bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 450bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 451bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 452bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 453bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", 454bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ticket->action); 455bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 456bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 457bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ticket++; 458bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 459bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 460bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (schedule_rx) 461bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi queue_work(iwm->rx_wq, &iwm->rx_worker); 462bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 463bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 464bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 465bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 466bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, 467bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 468bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 469bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_wifi_in_hdr *wifi_hdr; 470bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet; 471bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 id, buf_offset; 472bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 packet_size; 473c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi u8 id_hash; 474bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 4754fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_RX(iwm, DBG, "\n"); 476bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 477bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; 478bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); 479bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); 480bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); 481bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 4824fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", 4834fdd81f5f2e6fc55b67938f09b3495d679428cd7Zhu Yi wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); 484bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); 485bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); 486bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 487bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); 488bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (IS_ERR(packet)) 489bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return PTR_ERR(packet); 490bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 491c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi id_hash = IWM_RX_ID_GET_HASH(id); 492c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->packet_lock[id_hash]); 493c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi list_add_tail(&packet->node, &iwm->rx_packets[id_hash]); 494c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->packet_lock[id_hash]); 495bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 496bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* We might (unlikely) have received the packet _after_ the ticket */ 497bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi queue_work(iwm->rx_wq, &iwm->rx_worker); 498bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 499bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 500bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 501bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 502bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi/* MLME handlers */ 503bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, 504bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 505bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 506bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 507bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_assoc_start *start; 508bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 509bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi start = (struct iwm_umac_notif_assoc_start *)buf; 510bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 511bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", 512bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi start->bssid, le32_to_cpu(start->roam_reason)); 513bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 514bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wake_up_interruptible(&iwm->mlme_queue); 515bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 516bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 517bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 518bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 5199829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortizstatic u8 iwm_is_open_wep_profile(struct iwm_priv *iwm) 5209829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz{ 5219829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || 5229829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && 5239829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz (iwm->umac_profile->sec.ucast_cipher == 5249829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz iwm->umac_profile->sec.mcast_cipher) && 5259829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN)) 5269829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz return 1; 5279829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz 5289829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz return 0; 5299829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz} 5309829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz 531bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, 532bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 533bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 534bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 5357d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 5367d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi struct ieee80211_channel *chan; 537bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_assoc_complete *complete = 538bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_assoc_complete *)buf; 539bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 540bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", 541bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi complete->bssid, complete->status); 542bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 543bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (le32_to_cpu(complete->status)) { 544bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_ASSOC_COMPLETE_SUCCESS: 5457d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi chan = ieee80211_get_channel(wiphy, 54659eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf ieee80211_channel_to_frequency(complete->channel, 54759eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf complete->band == UMAC_BAND_2GHZ ? 54859eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf IEEE80211_BAND_2GHZ : 54959eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf IEEE80211_BAND_5GHZ)); 5507d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { 5517d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi /* Associated to a unallowed channel, disassociate. */ 5527d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi __iwm_invalidate_mlme_profile(iwm); 5537d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi IWM_WARN(iwm, "Couldn't associate with %pM due to " 5547d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi "channel %d is disabled. Check your local " 5557d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi "regulatory setting.\n", 5567d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi complete->bssid, complete->channel); 5577d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi goto failure; 5587d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi } 5597d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi 560bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); 561bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(iwm->bssid, complete->bssid, ETH_ALEN); 562bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->channel = complete->channel; 563bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 564de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi /* Internal roaming state, avoid notifying SME. */ 565de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) 566de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi && iwm->conf.mode == UMAC_MODE_BSS) { 567c7436273889e0ce511b317041f35344e92344885Zhu Yi cancel_delayed_work(&iwm->disconnect); 568ed9d01026f156db2d638cbb045231c7a8fde877dJouni Malinen cfg80211_roamed(iwm_to_ndev(iwm), NULL, 569de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi complete->bssid, 570de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi iwm->req_ie, iwm->req_ie_len, 571de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi iwm->resp_ie, iwm->resp_ie_len, 572de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi GFP_KERNEL); 573de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi break; 574de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi } 575de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi 576bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_link_on(iwm); 577bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 5789c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi if (iwm->conf.mode == UMAC_MODE_IBSS) 5799c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi goto ibss; 5809c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi 581d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) 582d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz cfg80211_connect_result(iwm_to_ndev(iwm), 583d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz complete->bssid, 584d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz iwm->req_ie, iwm->req_ie_len, 585d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz iwm->resp_ie, iwm->resp_ie_len, 586d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz WLAN_STATUS_SUCCESS, 587d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz GFP_KERNEL); 588d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz else 589ed9d01026f156db2d638cbb045231c7a8fde877dJouni Malinen cfg80211_roamed(iwm_to_ndev(iwm), NULL, 5909967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz complete->bssid, 591b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->req_ie, iwm->req_ie_len, 592b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->resp_ie, iwm->resp_ie_len, 593d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz GFP_KERNEL); 594bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 595bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_ASSOC_COMPLETE_FAILURE: 5967d49c6111c27f0e68b0310aeececf7ded53f7f94Zhu Yi failure: 597bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); 598bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memset(iwm->bssid, 0, ETH_ALEN); 599bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->channel = 0; 600bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 601de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi /* Internal roaming state, avoid notifying SME. */ 602de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) 603c7436273889e0ce511b317041f35344e92344885Zhu Yi && iwm->conf.mode == UMAC_MODE_BSS) { 604c7436273889e0ce511b317041f35344e92344885Zhu Yi cancel_delayed_work(&iwm->disconnect); 605de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi break; 606c7436273889e0ce511b317041f35344e92344885Zhu Yi } 607de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi 608bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_link_off(iwm); 6099967d46aa5ba065650d3352ab5d906f56ba17648Samuel Ortiz 6109c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi if (iwm->conf.mode == UMAC_MODE_IBSS) 6119c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi goto ibss; 6129c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi 613d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) 6149829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz if (!iwm_is_open_wep_profile(iwm)) { 6159829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz cfg80211_connect_result(iwm_to_ndev(iwm), 6169829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz complete->bssid, 6179829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz NULL, 0, NULL, 0, 6189829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz WLAN_STATUS_UNSPECIFIED_FAILURE, 6199829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz GFP_KERNEL); 6209829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz } else { 6219829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz /* Let's try shared WEP auth */ 6229829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz IWM_ERR(iwm, "Trying WEP shared auth\n"); 6239829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz schedule_work(&iwm->auth_retry_worker); 6249829e1b510214956bc9d5e278be49d781e1a6fbfSamuel Ortiz } 625d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz else 626d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, 627d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz GFP_KERNEL); 628de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi break; 629bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 630bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 631bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 632bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 633d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz clear_bit(IWM_STATUS_RESETTING, &iwm->status); 6349c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi return 0; 635bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 6369c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi ibss: 6379c7c0cdd24e64f9aed39453a1bffc3b3fd16ef99Zhu Yi cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); 638d210176eaaed0c7883caba52665bcfb5d420c660Samuel Ortiz clear_bit(IWM_STATUS_RESETTING, &iwm->status); 639bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 640bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 641bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 642bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, 643bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 644bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 645bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 646bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_profile_invalidate *invalid; 647c7436273889e0ce511b317041f35344e92344885Zhu Yi u32 reason; 648bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 649bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi invalid = (struct iwm_umac_notif_profile_invalidate *)buf; 650c7436273889e0ce511b317041f35344e92344885Zhu Yi reason = le32_to_cpu(invalid->reason); 651c7436273889e0ce511b317041f35344e92344885Zhu Yi 652c7436273889e0ce511b317041f35344e92344885Zhu Yi IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); 653bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 654c7436273889e0ce511b317041f35344e92344885Zhu Yi if (reason != UMAC_PROFILE_INVALID_REQUEST && 655c7436273889e0ce511b317041f35344e92344885Zhu Yi test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) 656c7436273889e0ce511b317041f35344e92344885Zhu Yi cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, 657c7436273889e0ce511b317041f35344e92344885Zhu Yi 0, WLAN_STATUS_UNSPECIFIED_FAILURE, 658c7436273889e0ce511b317041f35344e92344885Zhu Yi GFP_KERNEL); 659bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 660de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); 661bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); 662bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 6633db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell iwm->umac_profile_active = false; 664bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memset(iwm->bssid, 0, ETH_ALEN); 665bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->channel = 0; 666bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 667bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_link_off(iwm); 668bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 669bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wake_up_interruptible(&iwm->mlme_queue); 670bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 671bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 672bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 673bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 674c7436273889e0ce511b317041f35344e92344885Zhu Yi#define IWM_DISCONNECT_INTERVAL (5 * HZ) 675c7436273889e0ce511b317041f35344e92344885Zhu Yi 676c7436273889e0ce511b317041f35344e92344885Zhu Yistatic int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, 677c7436273889e0ce511b317041f35344e92344885Zhu Yi unsigned long buf_size, 678c7436273889e0ce511b317041f35344e92344885Zhu Yi struct iwm_wifi_cmd *cmd) 679c7436273889e0ce511b317041f35344e92344885Zhu Yi{ 680c7436273889e0ce511b317041f35344e92344885Zhu Yi IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); 681c7436273889e0ce511b317041f35344e92344885Zhu Yi 682c7436273889e0ce511b317041f35344e92344885Zhu Yi schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); 683c7436273889e0ce511b317041f35344e92344885Zhu Yi 684c7436273889e0ce511b317041f35344e92344885Zhu Yi return 0; 685c7436273889e0ce511b317041f35344e92344885Zhu Yi} 686c7436273889e0ce511b317041f35344e92344885Zhu Yi 687bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, 688bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 689bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 690bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 691bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int ret; 692bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_scan_complete *scan_complete = 693bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_scan_complete *)buf; 694bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 result = le32_to_cpu(scan_complete->result); 695bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 696bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", 697bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(scan_complete->type), 698bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(scan_complete->result), 699bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi scan_complete->seq_num); 700bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 701bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { 702bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Scan complete while device not scanning\n"); 703bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EIO; 704bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 705bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!iwm->scan_request) 706bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 707bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 708bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret = iwm_cfg80211_inform_bss(iwm); 709bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 710bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cfg80211_scan_done(iwm->scan_request, 711bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); 712bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->scan_request = NULL; 713bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 714bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ret; 715bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 716bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 717bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, 718bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 719bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 720bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 721bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_sta_info *umac_sta = 722bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_sta_info *)buf; 723bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_sta_info *sta; 724bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i; 725bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 726bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (le32_to_cpu(umac_sta->opcode)) { 727bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_OPCODE_ADD_MODIFY: 728bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; 729bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 730bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " 731bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "addr = %pM, qos = %d\n", 732bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sta->valid ? "Modify" : "Add", 733bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), 734bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), 735bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi umac_sta->mac_addr, 736bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi umac_sta->flags & UMAC_STA_FLAG_QOS); 737bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 7383db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell sta->valid = true; 739bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; 740bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); 741bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); 742bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 743bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_OPCODE_REMOVE: 744bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " 745bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "addr = %pM\n", 746bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), 747bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), 748bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi umac_sta->mac_addr); 749bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 750bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; 751bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 752bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) 7533db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell sta->valid = false; 754bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 755bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 756bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_OPCODE_CLEAR_ALL: 757bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < IWM_STA_TABLE_NUM; i++) 7583db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell iwm->sta_table[i].valid = false; 759bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 760bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 761bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 762bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 763bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 764bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 765bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 766bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 767bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 768b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yistatic int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf, 769b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi unsigned long buf_size, 770b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi struct iwm_wifi_cmd *cmd) 771b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi{ 772b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 773b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi 774b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n"); 775b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi 776b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi wiphy_rfkill_set_hw_state(wiphy, true); 777b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi 778b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi return 0; 779b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi} 780b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi 781bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, 782bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 783bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 784bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 785bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 786bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_mgmt *mgmt; 787bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_bss_info *umac_bss = 788bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_bss_info *)buf; 789bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_channel *channel; 790bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_supported_band *band; 79104d1c22761f33ac8f345665e7ef809c875142425Zhu Yi struct iwm_bss_info *bss; 792bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi s32 signal; 793bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int freq; 794bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 frame_len = le16_to_cpu(umac_bss->frame_len); 795bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; 796bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 797bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); 798bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 799bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); 800bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); 801bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", 802bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(umac_bss->timestamp)); 803bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", 804bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le16_to_cpu(umac_bss->table_idx)); 805bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); 806bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); 807bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); 808bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); 809bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 81004d1c22761f33ac8f345665e7ef809c875142425Zhu Yi list_for_each_entry(bss, &iwm->bss_list, node) 811bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (bss->bss->table_idx == umac_bss->table_idx) 812bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 813bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 814bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (&bss->node != &iwm->bss_list) { 815bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* Remove the old BSS entry, we will add it back later. */ 816bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_del(&bss->node); 817bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss->bss); 818bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else { 819bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* New BSS entry */ 820bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 821bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); 822bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!bss) { 823bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate bss_info\n"); 824bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -ENOMEM; 825bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 826bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 827bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 828bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi bss->bss = kzalloc(bss_len, GFP_KERNEL); 82933a5d083e786f0c3fb4efedb59b0e8e3de39963bRoel Kluin if (!bss->bss) { 830bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss); 831bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Couldn't allocate bss\n"); 832bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -ENOMEM; 833bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 834bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 835bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi INIT_LIST_HEAD(&bss->node); 836bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(bss->bss, umac_bss, bss_len); 837bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 838bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (umac_bss->band == UMAC_BAND_2GHZ) 839bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band = wiphy->bands[IEEE80211_BAND_2GHZ]; 840bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi else if (umac_bss->band == UMAC_BAND_5GHZ) 841bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band = wiphy->bands[IEEE80211_BAND_5GHZ]; 842bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi else { 843bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); 844bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi goto err; 845bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 846bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 84759eb21a6504731fc16db4cf9463065dd61093e08Bruno Randolf freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band); 848bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi channel = ieee80211_get_channel(wiphy, freq); 849bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi signal = umac_bss->rssi * 100; 850bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 851bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, 852bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mgmt, frame_len, 853bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi signal, GFP_KERNEL); 854bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!bss->cfg_bss) 855bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi goto err; 856bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 857bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_add_tail(&bss->node, &iwm->bss_list); 858bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 859bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 860bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi err: 861bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss->bss); 862bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss); 863bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 864bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 865bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 866bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 867bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, 868bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 869bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 870bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_bss_removed *bss_rm = 871bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_bss_removed *)buf; 872bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_bss_info *bss, *next; 873bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 table_idx; 874bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i; 875bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 876bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { 8771da3f88222579135569ad52d1c82a7393cf87178Zhu Yi table_idx = le16_to_cpu(bss_rm->entries[i]) & 8781da3f88222579135569ad52d1c82a7393cf87178Zhu Yi IWM_BSS_REMOVE_INDEX_MSK; 879bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_for_each_entry_safe(bss, next, &iwm->bss_list, node) 880bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (bss->bss->table_idx == cpu_to_le16(table_idx)) { 881bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_mgmt *mgmt; 882bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 883bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mgmt = (struct ieee80211_mgmt *) 884bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (bss->bss->frame_buf); 8851da3f88222579135569ad52d1c82a7393cf87178Zhu Yi IWM_DBG_MLME(iwm, ERR, "BSS removed: %pM\n", 886bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mgmt->bssid); 887bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_del(&bss->node); 888bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss->bss); 889bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(bss); 890bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 891bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 892bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 893bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 894bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 895bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 896bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, 897bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 898bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 899bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_mgt_frame *mgt_frame = 900b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi (struct iwm_umac_notif_mgt_frame *)buf; 901bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; 902bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 903bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, 904bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le16_to_cpu(mgt_frame->len)); 905bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 906bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (ieee80211_is_assoc_req(mgt->frame_control)) { 907d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches iwm->req_ie_len = le16_to_cpu(mgt_frame->len) 908d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches - offsetof(struct ieee80211_mgmt, 909d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches u.assoc_req.variable); 910b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi kfree(iwm->req_ie); 911b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, 912b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->req_ie_len, GFP_KERNEL); 913bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { 914d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches iwm->req_ie_len = le16_to_cpu(mgt_frame->len) 915d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches - offsetof(struct ieee80211_mgmt, 916d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches u.reassoc_req.variable); 917b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi kfree(iwm->req_ie); 918b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, 919b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->req_ie_len, GFP_KERNEL); 920bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { 921d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) 922d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches - offsetof(struct ieee80211_mgmt, 923d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches u.assoc_resp.variable); 924b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi kfree(iwm->resp_ie); 925b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, 926b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->resp_ie_len, GFP_KERNEL); 927bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { 928d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) 929d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches - offsetof(struct ieee80211_mgmt, 930d80050c4c321a74cea28c6ef9695d8427a928417Joe Perches u.reassoc_resp.variable); 931b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi kfree(iwm->resp_ie); 932b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, 933b68518fcbc6e0fe8c06a218cd2b92f62f3730cf9Zhu Yi iwm->resp_ie_len, GFP_KERNEL); 934bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else { 935de15fd31fcabb4b81a556736dd67ec4f71462f07Zhu Yi IWM_ERR(iwm, "Unsupported management frame: 0x%x", 93631452420ca956f2cf37f705c869e265c33894f07Zhu Yi le16_to_cpu(mgt->frame_control)); 937bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 938bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 939bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 940bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 941bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 942bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 943bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, 944bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 945bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 946bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_wifi_if *notif = 947bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_notif_wifi_if *)buf; 948bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 949bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (notif->status) { 950bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_ASSOC_START: 951bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); 952bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_ASSOC_COMPLETE: 953bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); 954bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: 955bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); 956bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_CONNECTION_TERMINATED: 957c7436273889e0ce511b317041f35344e92344885Zhu Yi return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); 958bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_SCAN_COMPLETE: 959bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); 960bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_STA_TABLE_CHANGE: 961bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); 962bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: 963bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); 964bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 965b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi case WIFI_IF_NTFY_RADIO_PREEMPTION: 966b8fcf590939f0aa24d43bdbdae7c963f31ba90bdZhu Yi return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd); 967bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: 968bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); 969bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: 970bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); 971bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 972bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_IF_NTFY_MGMT_FRAME: 973bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); 974bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: 975bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: 976bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: 977bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: 978bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: 979bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: 980bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_CNCT_ATC_START: 981bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: 982bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: 983bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: 984bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", 985bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi notif->status); 986bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 987bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 988bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); 989bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 990bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 991bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 992bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 993bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 994bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 995bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi#define IWM_STATS_UPDATE_INTERVAL (2 * HZ) 996bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 997bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, 998bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 999bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1000bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; 1001bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iw_statistics *wstats = &iwm->wstats; 1002bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 max_rate = 0; 1003bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i; 1004bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1005bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); 1006bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1007bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { 1008bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { 1009bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi max_rate = max_t(u16, max_rate, 1010bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi max(le16_to_cpu(stats->tx_rate[i]), 1011bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le16_to_cpu(stats->rx_rate[i]))); 1012bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1013bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* UMAC passes rate info multiplies by 2 */ 1014bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->rate = max_rate >> 1; 1015bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1016257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi iwm->txpower = le32_to_cpu(stats->tx_power); 1017bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1018bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->status = 0; 1019bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1020bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); 1021bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); 1022bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); 1023bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); 1024bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1025bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); 1026bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1027bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* according to cfg80211 */ 1028bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (stats->rssi_dbm < -110) 1029bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.qual = 0; 1030bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi else if (stats->rssi_dbm > -40) 1031bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.qual = 70; 1032bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi else 1033bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.qual = stats->rssi_dbm + 110; 1034bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1035bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.level = stats->rssi_dbm; 1036bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.noise = stats->noise_dbm; 1037bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 1038bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1039bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); 1040bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1041bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); 1042bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1043bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1044bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1045bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1046bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, 1047bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 1048bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 1049bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1050bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = 1051bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_cmd_eeprom_proxy *) 1052bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 1053bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; 1054bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 hdr_offset = le32_to_cpu(hdr->offset); 1055bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 hdr_len = le32_to_cpu(hdr->len); 1056bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 hdr_type = le32_to_cpu(hdr->type); 1057bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1058bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", 1059bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr_type, hdr_len, hdr_offset); 1060bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1061bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) 1062bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 1063bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1064bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (hdr_type) { 1065bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_UMAC_CMD_EEPROM_TYPE_READ: 1066bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); 1067bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1068bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: 1069bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 1070bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -ENOTSUPP; 1071bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1072bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1073bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1074bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1075bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1076bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, 1077bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 1078bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 1079bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1080bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_cmd_get_channel_list *ch_list = 1081bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (struct iwm_umac_cmd_get_channel_list *) 1082bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 1083bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 1084bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_supported_band *band; 1085bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int i; 1086bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1087bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band = wiphy->bands[IEEE80211_BAND_2GHZ]; 1088bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1089bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < band->n_channels; i++) { 1090bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long ch_mask_0 = 1091bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(ch_list->ch[0].channels_mask); 1092bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long ch_mask_2 = 1093bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(ch_list->ch[2].channels_mask); 1094bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1095bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!test_bit(i, &ch_mask_0)) 1096bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band->channels[i].flags |= IEEE80211_CHAN_DISABLED; 1097bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1098bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!test_bit(i, &ch_mask_2)) 1099bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; 1100bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1101bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1102bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band = wiphy->bands[IEEE80211_BAND_5GHZ]; 1103bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1104bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi for (i = 0; i < min(band->n_channels, 32); i++) { 1105bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long ch_mask_1 = 1106bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(ch_list->ch[1].channels_mask); 1107bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long ch_mask_3 = 1108bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le32_to_cpu(ch_list->ch[3].channels_mask); 1109bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1110bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!test_bit(i, &ch_mask_1)) 1111bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band->channels[i].flags |= IEEE80211_CHAN_DISABLED; 1112bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1113bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!test_bit(i, &ch_mask_3)) 1114bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; 1115bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1116bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1117bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1118bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1119bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1120a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortizstatic int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, 1121a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz unsigned long buf_size, 1122a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz struct iwm_wifi_cmd *cmd) 1123a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz{ 1124a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz struct iwm_umac_notif_stop_resume_tx *stp_res_tx = 1125a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz (struct iwm_umac_notif_stop_resume_tx *)buf; 1126a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz struct iwm_sta_info *sta_info; 1127a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz struct iwm_tid_info *tid_info; 1128a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id); 1129a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk); 1130a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz int bit, ret = 0; 1131a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz bool stop = false; 1132a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1133a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n" 1134a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz "\tflags: 0x%x\n" 1135a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz "\tSTA id: %d\n" 1136a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz "\tTID bitmask: 0x%x\n", 1137a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz stp_res_tx->flags, stp_res_tx->sta_id, 1138a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz stp_res_tx->stop_resume_tid_msk); 1139a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1140a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz if (stp_res_tx->flags & UMAC_STOP_TX_FLAG) 1141a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz stop = true; 1142a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1143a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz sta_info = &iwm->sta_table[sta_id]; 1144a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz if (!sta_info->valid) { 1145a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n", 1146a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz sta_id, stp_res_tx->sta_id); 1147a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz return -EINVAL; 1148a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz } 1149a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1150984b3f5746ed2cde3d184651dabf26980f2b66e5Akinobu Mita for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) { 1151a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz tid_info = &sta_info->tid_info[bit]; 1152a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1153a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz mutex_lock(&tid_info->mutex); 1154a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz tid_info->stopped = stop; 1155a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz mutex_unlock(&tid_info->mutex); 1156a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1157a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz if (!stop) { 1158a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz struct iwm_tx_queue *txq; 11598585c2b896861aacd15337c3c7e58ad114e6cf60Roel Kluin int queue = iwm_tid_to_queue(bit); 1160a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1161a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz if (queue < 0) 1162a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz continue; 1163a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1164a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz txq = &iwm->txq[queue]; 1165a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz /* 1166a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz * If we resume, we have to move our SKBs 1167a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz * back to the tx queue and queue some work. 1168a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz */ 1169a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz spin_lock_bh(&txq->lock); 1170a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz skb_queue_splice_init(&txq->queue, &txq->stopped_queue); 1171a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz spin_unlock_bh(&txq->lock); 1172a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1173a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz queue_work(txq->wq, &txq->worker); 1174a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz } 1175a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1176a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz } 1177a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1178a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz /* We send an ACK only for the stop case */ 1179a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz if (stop) 1180a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx); 1181a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1182a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz return ret; 1183a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz} 1184a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz 1185bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, 1186bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, 1187bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 1188bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1189708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz struct iwm_umac_wifi_if *hdr; 1190708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz 1191708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz if (cmd == NULL) { 1192708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz IWM_ERR(iwm, "Couldn't find expected wifi command\n"); 1193708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz return -EINVAL; 1194708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz } 1195708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz 1196708567e0723f3a217286c2b60805af6de360ec50Samuel Ortiz hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload; 1197bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1198bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " 1199a70742f167424bab794ca74b9e99b598b358bb7dSamuel Ortiz "oid is 0x%x\n", hdr->oid); 1200a70742f167424bab794ca74b9e99b598b358bb7dSamuel Ortiz 120113eb670c104e15e06d38f3a210cfaf467a9c66deJohn W. Linville set_bit(hdr->oid, &iwm->wifi_ntfy[0]); 120213eb670c104e15e06d38f3a210cfaf467a9c66deJohn W. Linville wake_up_interruptible(&iwm->wifi_ntfy_queue); 1203bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1204bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (hdr->oid) { 1205bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_WIFI_IF_CMD_SET_PROFILE: 12063db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell iwm->umac_profile_active = true; 1207bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1208bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 1209bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1210bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1211bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1212bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1213bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1214bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1215e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz#define CT_KILL_DELAY (30 * HZ) 1216bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, 1217bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size, struct iwm_wifi_cmd *cmd) 1218bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1219257862f3faef397f1a677ae6a5a1828fa00a97b1Zhu Yi struct wiphy *wiphy = iwm_to_wiphy(iwm); 1220bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) 1221bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 1222bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 flags = le32_to_cpu(state->flags); 1223bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1224bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", 1225bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", 1226bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); 1227bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1228e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz if (flags & IWM_CARD_STATE_CTKILL_DISABLED) { 1229e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz /* 1230e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz * We got a CTKILL event: We bring the interface down in 1231e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz * oder to cool the device down, and try to bring it up 1232e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz * 30 seconds later. If it's still too hot, we'll go through 1233e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz * this code path again. 1234e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz */ 1235e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz cancel_delayed_work_sync(&iwm->ct_kill_delay); 1236e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY); 1237e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz } 1238e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz 1239e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz wiphy_rfkill_set_hw_state(wiphy, flags & 1240e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz (IWM_CARD_STATE_HW_DISABLED | 1241e85498b21d0372a00f31ab9f7c0d215c32c9fad5Samuel Ortiz IWM_CARD_STATE_CTKILL_DISABLED)); 1242bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1243bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1244bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1245bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1246bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, 1247bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size) 1248bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1249bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_wifi_in_hdr *wifi_hdr; 1250bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd; 1251bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 source, cmd_id; 1252bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u16 seq_num; 1253bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 count; 1254bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1255bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; 1256bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cmd_id = wifi_hdr->sw_hdr.cmd.cmd; 1257bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); 1258bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (source >= IWM_SRC_NUM) { 1259bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_CRIT(iwm, "invalid source %d\n", source); 1260bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 1261bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1262bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 126334dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi if (cmd_id == REPLY_RX_MPDU_CMD) 126434dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi trace_iwm_rx_packet(iwm, buf, buf_size); 126534dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi else if ((cmd_id == UMAC_NOTIFY_OPCODE_RX_TICKET) && 126634dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi (source == UMAC_HDI_IN_SOURCE_FW)) 126734dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi trace_iwm_rx_ticket(iwm, buf, buf_size); 126834dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi else 126934dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi trace_iwm_rx_wifi_cmd(iwm, wifi_hdr); 127034dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi 127134dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi count = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT); 1272bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi count += sizeof(struct iwm_umac_wifi_in_hdr) - 1273bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi sizeof(struct iwm_dev_cmd_hdr); 1274bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (count > buf_size) { 1275bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); 1276bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 1277bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1278bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1279bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); 1280bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1281bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", 1282bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cmd_id, source, seq_num); 1283bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1284bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* 1285bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * If this is a response to a previously sent command, there must 1286bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * be a pending command for this sequence number. 1287bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 1288bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); 1289bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1290bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* Notify the caller only for sync commands. */ 1291bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (source) { 1292bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_FHRX: 1293bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (iwm->lmac_handlers[cmd_id] && 1294bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi test_bit(cmd_id, &iwm->lmac_handler_map[0])) 1295bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_notif_send(iwm, cmd, cmd_id, source, 1296bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf, count); 1297bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1298bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_FW: 1299bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (iwm->umac_handlers[cmd_id] && 1300bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi test_bit(cmd_id, &iwm->umac_handler_map[0])) 1301bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_notif_send(iwm, cmd, cmd_id, source, 1302bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf, count); 1303bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1304bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_UDMA: 1305bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1306bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1307bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1308bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_rx_handle_resp(iwm, buf, count, cmd); 1309bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1310bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1311bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yiint iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, 1312bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_wifi_cmd *cmd) 1313bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1314bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 source, cmd_id; 1315bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_umac_wifi_in_hdr *wifi_hdr; 1316bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int ret = 0; 1317bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1318bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; 1319bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cmd_id = wifi_hdr->sw_hdr.cmd.cmd; 1320bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1321bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); 1322bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1323bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); 1324bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1325bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (source) { 1326bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_FHRX: 1327bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (iwm->lmac_handlers[cmd_id]) 1328bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret = iwm->lmac_handlers[cmd_id] 1329bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (iwm, buf, buf_size, cmd); 1330bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1331bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_FW: 1332bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (iwm->umac_handlers[cmd_id]) 1333bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret = iwm->umac_handlers[cmd_id] 1334bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (iwm, buf, buf_size, cmd); 1335bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1336bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_HDI_IN_SOURCE_UDMA: 1337bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret = -EINVAL; 1338bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1339bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1340bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1341bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(cmd); 1342bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1343bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ret; 1344bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1345bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1346bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, 1347bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size) 1348bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1349bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 seq_num; 1350bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; 135104d1c22761f33ac8f345665e7ef809c875142425Zhu Yi struct iwm_nonwifi_cmd *cmd; 1352bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 135334dd5feb8b8b15654714731e1dbb34a6d37fb34eZhu Yi trace_iwm_rx_nonwifi_cmd(iwm, buf, buf_size); 1354bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); 1355bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1356bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* 1357bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * We received a non wifi answer. 1358bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Let's check if there's a pending command for it, and if so 1359bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * replace the command payload with the buffer, and then wake the 1360bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * callers up. 1361bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * That means we only support synchronised non wifi command response 1362bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * schemes. 1363bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 136404d1c22761f33ac8f345665e7ef809c875142425Zhu Yi list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) 1365bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (cmd->seq_num == seq_num) { 13663db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell cmd->resp_received = true; 1367bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi cmd->buf.len = buf_size; 1368bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memcpy(cmd->buf.hdr, buf, buf_size); 1369bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi wake_up_interruptible(&iwm->nonwifi_queue); 1370bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1371bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1372bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1373bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1374bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1375bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, 1376bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_size) 1377bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1378bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int ret = 0; 1379bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 op_code; 1380bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned long buf_offset = 0; 1381bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_udma_in_hdr *hdr; 1382bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1383bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* 1384bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * To allow for a more efficient bus usage, UMAC 1385bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * messages are encapsulated into UDMA ones. This 1386bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * way we can have several UMAC messages in one bus 1387bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * transfer. 1388bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * A UDMA frame size is always aligned on 16 bytes, 1389bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * and a UDMA frame must not start with a UMAC_PAD_TERMINAL 1390bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * word. This is how we parse a bus frame into several 1391bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * UDMA ones. 1392bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 1393bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi while (buf_offset < buf_size) { 1394bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1395bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); 1396bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1397bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (iwm_rx_check_udma_hdr(hdr) < 0) { 1398bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "End of frame\n"); 1399bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1400bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1401bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1402bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); 1403bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1404bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); 1405bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1406bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { 1407bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, 1408bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf_size - buf_offset); 1409bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { 1410bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (GET_VAL32(hdr->cmd, 1411bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != 1412bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { 1413bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Incorrect hw signature\n"); 1414bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return -EINVAL; 1415bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1416bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, 1417bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf_size - buf_offset); 1418bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else { 1419bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); 1420bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret |= -EINVAL; 1421bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1422bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1423bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi buf_offset += iwm_rx_resp_size(hdr); 1424bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1425bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1426bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return ret; 1427bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1428bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1429bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yiint iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) 1430bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1431bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_udma_in_hdr *hdr; 1432bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1433bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct iwm_udma_in_hdr *)buf; 1434bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1435bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (le32_to_cpu(hdr->cmd)) { 1436bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_REBOOT_BARKER: 14377fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz if (test_bit(IWM_STATUS_READY, &iwm->status)) { 14387fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz IWM_ERR(iwm, "Unexpected BARKER\n"); 14397fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz 14407fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz schedule_work(&iwm->reset_worker); 14417fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz 14427fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz return 0; 14437fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz } 14447fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9eSamuel Ortiz 1445bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, 1446bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_SRC_UDMA, buf, buf_size); 1447bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case UMAC_ACK_BARKER: 1448bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, 1449bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_SRC_UDMA, NULL, 0); 1450bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 1451bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); 1452bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return iwm_rx_handle_umac(iwm, buf, buf_size); 1453bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1454bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1455bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return 0; 1456bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1457bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1458bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic const iwm_handler iwm_umac_handlers[] = 1459bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1460bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, 1461bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, 1462bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, 1463bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, 1464bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, 1465bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, 1466bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, 1467bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, 1468bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, 1469bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, 1470bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, 1471a7af530d45969a63e20708417b70c547596ce3a9Samuel Ortiz [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx, 1472bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, 1473bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, 1474bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}; 1475bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1476bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic const iwm_handler iwm_lmac_handlers[] = 1477bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1478bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [REPLY_TX] = iwm_ntf_tx, 1479bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [REPLY_ALIVE] = iwm_ntf_lmac_version, 1480bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, 1481bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, 1482bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, 1483bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, 1484bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, 1485bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi}; 1486bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1487bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yivoid iwm_rx_setup_handlers(struct iwm_priv *iwm) 1488bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1489bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; 1490bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; 1491bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1492bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1493bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) 1494bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1495bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_hdr *hdr; 1496bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi unsigned int hdr_len; 1497bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1498bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct ieee80211_hdr *)skb->data; 1499bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1500bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!ieee80211_has_protected(hdr->frame_control)) 1501bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return; 1502bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1503bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr_len = ieee80211_hdrlen(hdr->frame_control); 1504bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (hdr_total_len <= hdr_len) 1505bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi return; 1506bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1507bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); 1508bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb_pull(skb, (hdr_total_len - hdr_len)); 1509bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1510bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1511bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic void iwm_rx_adjust_packet(struct iwm_priv *iwm, 1512bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet, 1513bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket_node) 1514bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1515bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u32 payload_offset = 0, payload_len; 1516bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket *ticket = ticket_node->ticket; 1517bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_mpdu_hdr *mpdu_hdr; 1518bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_hdr *hdr; 1519bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1520bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; 1521bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi payload_offset += sizeof(struct iwm_rx_mpdu_hdr); 1522bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* Padding is 0 or 2 bytes */ 1523bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi payload_len = le16_to_cpu(mpdu_hdr->len) + 1524bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); 1525bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi payload_len -= ticket->tail_len; 1526bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1527bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " 1528bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "ticket offset:%d ticket tail len:%d\n", 1529bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi payload_len, payload_offset, ticket->payload_offset, 1530bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ticket->tail_len); 1531bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1532bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); 1533bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1534bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb_pull(packet->skb, payload_offset); 1535bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb_trim(packet->skb, payload_len); 1536bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1537bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_remove_iv(packet->skb, ticket->payload_offset); 1538bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1539bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct ieee80211_hdr *) packet->skb->data; 1540bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (ieee80211_is_data_qos(hdr->frame_control)) { 1541bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* UMAC handed QOS_DATA frame with 2 padding bytes appended 1542bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * to the qos_ctl field in IEEE 802.11 headers. */ 1543bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, 1544bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet->skb->data, 1545bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ieee80211_hdrlen(hdr->frame_control) - 1546bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IEEE80211_QOS_CTL_LEN); 1547bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, 1548bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IEEE80211_QOS_CTL_LEN + 2); 1549bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 1550bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1551bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1552bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", 1553bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi packet->skb->data, packet->skb->len); 1554bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1555bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1556bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic void classify8023(struct sk_buff *skb) 1557bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1558bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1559bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1560bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (ieee80211_is_data_qos(hdr->frame_control)) { 1561bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi u8 *qc = ieee80211_get_qos_ctl(hdr); 1562bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* frame has qos control */ 1563bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; 1564bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } else { 1565bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb->priority = 0; 1566bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1567bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1568bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 156918974b5b0b5e758d416c550553b143e5c8038281Zhu Yistatic void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) 157018974b5b0b5e758d416c550553b143e5c8038281Zhu Yi{ 157118974b5b0b5e758d416c550553b143e5c8038281Zhu Yi struct wireless_dev *wdev = iwm_to_wdev(iwm); 157218974b5b0b5e758d416c550553b143e5c8038281Zhu Yi struct net_device *ndev = iwm_to_ndev(iwm); 157318974b5b0b5e758d416c550553b143e5c8038281Zhu Yi struct sk_buff_head list; 157418974b5b0b5e758d416c550553b143e5c8038281Zhu Yi struct sk_buff *frame; 157518974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 157618974b5b0b5e758d416c550553b143e5c8038281Zhu Yi IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); 157718974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 157818974b5b0b5e758d416c550553b143e5c8038281Zhu Yi __skb_queue_head_init(&list); 15798b3becadc82de3b87a5c196239db3fef6caa9c82Yogesh Ashok Powar ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0, 15808b3becadc82de3b87a5c196239db3fef6caa9c82Yogesh Ashok Powar true); 158118974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 158218974b5b0b5e758d416c550553b143e5c8038281Zhu Yi while ((frame = __skb_dequeue(&list))) { 158318974b5b0b5e758d416c550553b143e5c8038281Zhu Yi ndev->stats.rx_packets++; 158418974b5b0b5e758d416c550553b143e5c8038281Zhu Yi ndev->stats.rx_bytes += frame->len; 158518974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 158618974b5b0b5e758d416c550553b143e5c8038281Zhu Yi frame->protocol = eth_type_trans(frame, ndev); 158718974b5b0b5e758d416c550553b143e5c8038281Zhu Yi frame->ip_summed = CHECKSUM_NONE; 158818974b5b0b5e758d416c550553b143e5c8038281Zhu Yi memset(frame->cb, 0, sizeof(frame->cb)); 158918974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 159018974b5b0b5e758d416c550553b143e5c8038281Zhu Yi if (netif_rx_ni(frame) == NET_RX_DROP) { 159118974b5b0b5e758d416c550553b143e5c8038281Zhu Yi IWM_ERR(iwm, "Packet dropped\n"); 159218974b5b0b5e758d416c550553b143e5c8038281Zhu Yi ndev->stats.rx_dropped++; 159318974b5b0b5e758d416c550553b143e5c8038281Zhu Yi } 159418974b5b0b5e758d416c550553b143e5c8038281Zhu Yi } 159518974b5b0b5e758d416c550553b143e5c8038281Zhu Yi} 159618974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 1597bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yistatic void iwm_rx_process_packet(struct iwm_priv *iwm, 1598bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet, 1599bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket_node) 1600bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1601bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi int ret; 1602bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct sk_buff *skb = packet->skb; 1603bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct wireless_dev *wdev = iwm_to_wdev(iwm); 1604bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct net_device *ndev = iwm_to_ndev(iwm); 1605bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1606bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); 1607bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1608bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi switch (le16_to_cpu(ticket_node->ticket->action)) { 1609bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_RX_TICKET_RELEASE: 1610bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); 161118974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 1612bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_rx_adjust_packet(iwm, packet, ticket_node); 161318974b5b0b5e758d416c550553b143e5c8038281Zhu Yi skb->dev = iwm_to_ndev(iwm); 161418974b5b0b5e758d416c550553b143e5c8038281Zhu Yi classify8023(skb); 161518974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 161618974b5b0b5e758d416c550553b143e5c8038281Zhu Yi if (le16_to_cpu(ticket_node->ticket->flags) & 161718974b5b0b5e758d416c550553b143e5c8038281Zhu Yi IWM_RX_TICKET_AMSDU_MSK) { 161818974b5b0b5e758d416c550553b143e5c8038281Zhu Yi iwm_rx_process_amsdu(iwm, skb); 161918974b5b0b5e758d416c550553b143e5c8038281Zhu Yi break; 162018974b5b0b5e758d416c550553b143e5c8038281Zhu Yi } 162118974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 1622bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); 1623bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (ret < 0) { 1624bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " 1625bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "%d\n", ret); 162618974b5b0b5e758d416c550553b143e5c8038281Zhu Yi kfree_skb(packet->skb); 1627bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1628bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1629bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1630bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); 1631bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 163218974b5b0b5e758d416c550553b143e5c8038281Zhu Yi ndev->stats.rx_packets++; 163318974b5b0b5e758d416c550553b143e5c8038281Zhu Yi ndev->stats.rx_bytes += skb->len; 163418974b5b0b5e758d416c550553b143e5c8038281Zhu Yi 1635bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi skb->protocol = eth_type_trans(skb, ndev); 16363a0e4851c97328ee455a57cb3e4097bb43934a87Zhu Yi skb->ip_summed = CHECKSUM_NONE; 1637bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi memset(skb->cb, 0, sizeof(skb->cb)); 1638bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1639dd13fd649879b6230be5d855e00c286c5e60f354Zhu Yi if (netif_rx_ni(skb) == NET_RX_DROP) { 1640bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_ERR(iwm, "Packet dropped\n"); 1641bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi ndev->stats.rx_dropped++; 1642bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1643bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1644bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi case IWM_RX_TICKET_DROP: 164569cf6e2d5bd90436a0fa6cef2f4d65583faef388Samuel Ortiz IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n", 164669cf6e2d5bd90436a0fa6cef2f4d65583faef388Samuel Ortiz le16_to_cpu(ticket_node->ticket->flags)); 1647bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree_skb(packet->skb); 1648bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi break; 1649bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi default: 1650af901ca181d92aac3a7dc265144a9081a86d8f39André Goddard Rosa IWM_ERR(iwm, "Unknown ticket action: %d\n", 1651bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le16_to_cpu(ticket_node->ticket->action)); 1652bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree_skb(packet->skb); 1653bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1654bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1655bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi kfree(packet); 1656bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_rx_ticket_node_free(ticket_node); 1657bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1658bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1659bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi/* 1660bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * Rx data processing: 1661bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * 1662bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * We're receiving Rx packet from the LMAC, and Rx ticket from 1663bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * the UMAC. 1664bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * To forward a target data packet upstream (i.e. to the 1665bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * kernel network stack), we must have received an Rx ticket 1666bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * that tells us we're allowed to release this packet (ticket 1667bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, 1668bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * among other things, where valid data actually starts in the Rx 1669bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * packet. 1670bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 1671bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yivoid iwm_rx_worker(struct work_struct *work) 1672bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi{ 1673bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_priv *iwm; 1674bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_ticket_node *ticket, *next; 1675bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1676bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm = container_of(work, struct iwm_priv, rx_worker); 1677bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1678bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi /* 1679bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * We go through the tickets list and if there is a pending 1680bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * packet for it, we push it upstream. 1681bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * We stop whenever a ticket is missing its packet, as we're 1682bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi * supposed to send the packets in order. 1683bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi */ 1684c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_lock(&iwm->ticket_lock); 1685bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { 1686bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi struct iwm_rx_packet *packet = 1687bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); 1688bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1689bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi if (!packet) { 1690bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " 1691bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi "to be handled first\n", 1692bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi le16_to_cpu(ticket->ticket->id)); 1693c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi break; 1694bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1695bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1696bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi list_del(&ticket->node); 1697bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi iwm_rx_process_packet(iwm, packet, ticket); 1698bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi } 1699c03c6aefdc2c1f5785a5b0d1a3f7e48eeaae3505Zhu Yi spin_unlock(&iwm->ticket_lock); 1700bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi} 1701bb9f8692f5043efef0dcef048cdd1db68299c2cbZhu Yi 1702