17ac9a364SKalle Valo /****************************************************************************** 27ac9a364SKalle Valo * 37ac9a364SKalle Valo * GPL LICENSE SUMMARY 47ac9a364SKalle Valo * 57ac9a364SKalle Valo * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 67ac9a364SKalle Valo * 77ac9a364SKalle Valo * This program is free software; you can redistribute it and/or modify 87ac9a364SKalle Valo * it under the terms of version 2 of the GNU General Public License as 97ac9a364SKalle Valo * published by the Free Software Foundation. 107ac9a364SKalle Valo * 117ac9a364SKalle Valo * This program is distributed in the hope that it will be useful, but 127ac9a364SKalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of 137ac9a364SKalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 147ac9a364SKalle Valo * General Public License for more details. 157ac9a364SKalle Valo * 167ac9a364SKalle Valo * You should have received a copy of the GNU General Public License 177ac9a364SKalle Valo * along with this program; if not, write to the Free Software 187ac9a364SKalle Valo * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 197ac9a364SKalle Valo * USA 207ac9a364SKalle Valo * 217ac9a364SKalle Valo * The full GNU General Public License is included in this distribution 227ac9a364SKalle Valo * in the file called LICENSE.GPL. 237ac9a364SKalle Valo * 247ac9a364SKalle Valo * Contact Information: 257ac9a364SKalle Valo * Intel Linux Wireless <ilw@linux.intel.com> 267ac9a364SKalle Valo * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 277ac9a364SKalle Valo *****************************************************************************/ 287ac9a364SKalle Valo 297ac9a364SKalle Valo #include <linux/kernel.h> 307ac9a364SKalle Valo #include <linux/module.h> 317ac9a364SKalle Valo #include <linux/etherdevice.h> 327ac9a364SKalle Valo #include <linux/sched.h> 337ac9a364SKalle Valo #include <linux/slab.h> 347ac9a364SKalle Valo #include <linux/types.h> 357ac9a364SKalle Valo #include <linux/lockdep.h> 367ac9a364SKalle Valo #include <linux/pci.h> 377ac9a364SKalle Valo #include <linux/dma-mapping.h> 387ac9a364SKalle Valo #include <linux/delay.h> 397ac9a364SKalle Valo #include <linux/skbuff.h> 407ac9a364SKalle Valo #include <net/mac80211.h> 417ac9a364SKalle Valo 427ac9a364SKalle Valo #include "common.h" 437ac9a364SKalle Valo 447ac9a364SKalle Valo int 457ac9a364SKalle Valo _il_poll_bit(struct il_priv *il, u32 addr, u32 bits, u32 mask, int timeout) 467ac9a364SKalle Valo { 477ac9a364SKalle Valo const int interval = 10; /* microseconds */ 487ac9a364SKalle Valo int t = 0; 497ac9a364SKalle Valo 507ac9a364SKalle Valo do { 517ac9a364SKalle Valo if ((_il_rd(il, addr) & mask) == (bits & mask)) 527ac9a364SKalle Valo return t; 537ac9a364SKalle Valo udelay(interval); 547ac9a364SKalle Valo t += interval; 557ac9a364SKalle Valo } while (t < timeout); 567ac9a364SKalle Valo 577ac9a364SKalle Valo return -ETIMEDOUT; 587ac9a364SKalle Valo } 597ac9a364SKalle Valo EXPORT_SYMBOL(_il_poll_bit); 607ac9a364SKalle Valo 617ac9a364SKalle Valo void 627ac9a364SKalle Valo il_set_bit(struct il_priv *p, u32 r, u32 m) 637ac9a364SKalle Valo { 647ac9a364SKalle Valo unsigned long reg_flags; 657ac9a364SKalle Valo 667ac9a364SKalle Valo spin_lock_irqsave(&p->reg_lock, reg_flags); 677ac9a364SKalle Valo _il_set_bit(p, r, m); 687ac9a364SKalle Valo spin_unlock_irqrestore(&p->reg_lock, reg_flags); 697ac9a364SKalle Valo } 707ac9a364SKalle Valo EXPORT_SYMBOL(il_set_bit); 717ac9a364SKalle Valo 727ac9a364SKalle Valo void 737ac9a364SKalle Valo il_clear_bit(struct il_priv *p, u32 r, u32 m) 747ac9a364SKalle Valo { 757ac9a364SKalle Valo unsigned long reg_flags; 767ac9a364SKalle Valo 777ac9a364SKalle Valo spin_lock_irqsave(&p->reg_lock, reg_flags); 787ac9a364SKalle Valo _il_clear_bit(p, r, m); 797ac9a364SKalle Valo spin_unlock_irqrestore(&p->reg_lock, reg_flags); 807ac9a364SKalle Valo } 817ac9a364SKalle Valo EXPORT_SYMBOL(il_clear_bit); 827ac9a364SKalle Valo 837ac9a364SKalle Valo bool 847ac9a364SKalle Valo _il_grab_nic_access(struct il_priv *il) 857ac9a364SKalle Valo { 867ac9a364SKalle Valo int ret; 877ac9a364SKalle Valo u32 val; 887ac9a364SKalle Valo 897ac9a364SKalle Valo /* this bit wakes up the NIC */ 907ac9a364SKalle Valo _il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 917ac9a364SKalle Valo 927ac9a364SKalle Valo /* 937ac9a364SKalle Valo * These bits say the device is running, and should keep running for 947ac9a364SKalle Valo * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), 957ac9a364SKalle Valo * but they do not indicate that embedded SRAM is restored yet; 967ac9a364SKalle Valo * 3945 and 4965 have volatile SRAM, and must save/restore contents 977ac9a364SKalle Valo * to/from host DRAM when sleeping/waking for power-saving. 987ac9a364SKalle Valo * Each direction takes approximately 1/4 millisecond; with this 997ac9a364SKalle Valo * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a 1007ac9a364SKalle Valo * series of register accesses are expected (e.g. reading Event Log), 1017ac9a364SKalle Valo * to keep device from sleeping. 1027ac9a364SKalle Valo * 1037ac9a364SKalle Valo * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that 1047ac9a364SKalle Valo * SRAM is okay/restored. We don't check that here because this call 1057ac9a364SKalle Valo * is just for hardware register access; but GP1 MAC_SLEEP check is a 1067ac9a364SKalle Valo * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). 1077ac9a364SKalle Valo * 1087ac9a364SKalle Valo */ 1097ac9a364SKalle Valo ret = 1107ac9a364SKalle Valo _il_poll_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, 1117ac9a364SKalle Valo (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | 1127ac9a364SKalle Valo CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); 1137ac9a364SKalle Valo if (unlikely(ret < 0)) { 1147ac9a364SKalle Valo val = _il_rd(il, CSR_GP_CNTRL); 1157ac9a364SKalle Valo WARN_ONCE(1, "Timeout waiting for ucode processor access " 1167ac9a364SKalle Valo "(CSR_GP_CNTRL 0x%08x)\n", val); 1177ac9a364SKalle Valo _il_wr(il, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); 1187ac9a364SKalle Valo return false; 1197ac9a364SKalle Valo } 1207ac9a364SKalle Valo 1217ac9a364SKalle Valo return true; 1227ac9a364SKalle Valo } 1237ac9a364SKalle Valo EXPORT_SYMBOL_GPL(_il_grab_nic_access); 1247ac9a364SKalle Valo 1257ac9a364SKalle Valo int 1267ac9a364SKalle Valo il_poll_bit(struct il_priv *il, u32 addr, u32 mask, int timeout) 1277ac9a364SKalle Valo { 1287ac9a364SKalle Valo const int interval = 10; /* microseconds */ 1297ac9a364SKalle Valo int t = 0; 1307ac9a364SKalle Valo 1317ac9a364SKalle Valo do { 1327ac9a364SKalle Valo if ((il_rd(il, addr) & mask) == mask) 1337ac9a364SKalle Valo return t; 1347ac9a364SKalle Valo udelay(interval); 1357ac9a364SKalle Valo t += interval; 1367ac9a364SKalle Valo } while (t < timeout); 1377ac9a364SKalle Valo 1387ac9a364SKalle Valo return -ETIMEDOUT; 1397ac9a364SKalle Valo } 1407ac9a364SKalle Valo EXPORT_SYMBOL(il_poll_bit); 1417ac9a364SKalle Valo 1427ac9a364SKalle Valo u32 1437ac9a364SKalle Valo il_rd_prph(struct il_priv *il, u32 reg) 1447ac9a364SKalle Valo { 1457ac9a364SKalle Valo unsigned long reg_flags; 1467ac9a364SKalle Valo u32 val; 1477ac9a364SKalle Valo 1487ac9a364SKalle Valo spin_lock_irqsave(&il->reg_lock, reg_flags); 1497ac9a364SKalle Valo _il_grab_nic_access(il); 1507ac9a364SKalle Valo val = _il_rd_prph(il, reg); 1517ac9a364SKalle Valo _il_release_nic_access(il); 1527ac9a364SKalle Valo spin_unlock_irqrestore(&il->reg_lock, reg_flags); 1537ac9a364SKalle Valo return val; 1547ac9a364SKalle Valo } 1557ac9a364SKalle Valo EXPORT_SYMBOL(il_rd_prph); 1567ac9a364SKalle Valo 1577ac9a364SKalle Valo void 1587ac9a364SKalle Valo il_wr_prph(struct il_priv *il, u32 addr, u32 val) 1597ac9a364SKalle Valo { 1607ac9a364SKalle Valo unsigned long reg_flags; 1617ac9a364SKalle Valo 1627ac9a364SKalle Valo spin_lock_irqsave(&il->reg_lock, reg_flags); 1637ac9a364SKalle Valo if (likely(_il_grab_nic_access(il))) { 1647ac9a364SKalle Valo _il_wr_prph(il, addr, val); 1657ac9a364SKalle Valo _il_release_nic_access(il); 1667ac9a364SKalle Valo } 1677ac9a364SKalle Valo spin_unlock_irqrestore(&il->reg_lock, reg_flags); 1687ac9a364SKalle Valo } 1697ac9a364SKalle Valo EXPORT_SYMBOL(il_wr_prph); 1707ac9a364SKalle Valo 1717ac9a364SKalle Valo u32 1727ac9a364SKalle Valo il_read_targ_mem(struct il_priv *il, u32 addr) 1737ac9a364SKalle Valo { 1747ac9a364SKalle Valo unsigned long reg_flags; 1757ac9a364SKalle Valo u32 value; 1767ac9a364SKalle Valo 1777ac9a364SKalle Valo spin_lock_irqsave(&il->reg_lock, reg_flags); 1787ac9a364SKalle Valo _il_grab_nic_access(il); 1797ac9a364SKalle Valo 1807ac9a364SKalle Valo _il_wr(il, HBUS_TARG_MEM_RADDR, addr); 1817ac9a364SKalle Valo value = _il_rd(il, HBUS_TARG_MEM_RDAT); 1827ac9a364SKalle Valo 1837ac9a364SKalle Valo _il_release_nic_access(il); 1847ac9a364SKalle Valo spin_unlock_irqrestore(&il->reg_lock, reg_flags); 1857ac9a364SKalle Valo return value; 1867ac9a364SKalle Valo } 1877ac9a364SKalle Valo EXPORT_SYMBOL(il_read_targ_mem); 1887ac9a364SKalle Valo 1897ac9a364SKalle Valo void 1907ac9a364SKalle Valo il_write_targ_mem(struct il_priv *il, u32 addr, u32 val) 1917ac9a364SKalle Valo { 1927ac9a364SKalle Valo unsigned long reg_flags; 1937ac9a364SKalle Valo 1947ac9a364SKalle Valo spin_lock_irqsave(&il->reg_lock, reg_flags); 1957ac9a364SKalle Valo if (likely(_il_grab_nic_access(il))) { 1967ac9a364SKalle Valo _il_wr(il, HBUS_TARG_MEM_WADDR, addr); 1977ac9a364SKalle Valo _il_wr(il, HBUS_TARG_MEM_WDAT, val); 1987ac9a364SKalle Valo _il_release_nic_access(il); 1997ac9a364SKalle Valo } 2007ac9a364SKalle Valo spin_unlock_irqrestore(&il->reg_lock, reg_flags); 2017ac9a364SKalle Valo } 2027ac9a364SKalle Valo EXPORT_SYMBOL(il_write_targ_mem); 2037ac9a364SKalle Valo 2047ac9a364SKalle Valo const char * 2057ac9a364SKalle Valo il_get_cmd_string(u8 cmd) 2067ac9a364SKalle Valo { 2077ac9a364SKalle Valo switch (cmd) { 2087ac9a364SKalle Valo IL_CMD(N_ALIVE); 2097ac9a364SKalle Valo IL_CMD(N_ERROR); 2107ac9a364SKalle Valo IL_CMD(C_RXON); 2117ac9a364SKalle Valo IL_CMD(C_RXON_ASSOC); 2127ac9a364SKalle Valo IL_CMD(C_QOS_PARAM); 2137ac9a364SKalle Valo IL_CMD(C_RXON_TIMING); 2147ac9a364SKalle Valo IL_CMD(C_ADD_STA); 2157ac9a364SKalle Valo IL_CMD(C_REM_STA); 2167ac9a364SKalle Valo IL_CMD(C_WEPKEY); 2177ac9a364SKalle Valo IL_CMD(N_3945_RX); 2187ac9a364SKalle Valo IL_CMD(C_TX); 2197ac9a364SKalle Valo IL_CMD(C_RATE_SCALE); 2207ac9a364SKalle Valo IL_CMD(C_LEDS); 2217ac9a364SKalle Valo IL_CMD(C_TX_LINK_QUALITY_CMD); 2227ac9a364SKalle Valo IL_CMD(C_CHANNEL_SWITCH); 2237ac9a364SKalle Valo IL_CMD(N_CHANNEL_SWITCH); 2247ac9a364SKalle Valo IL_CMD(C_SPECTRUM_MEASUREMENT); 2257ac9a364SKalle Valo IL_CMD(N_SPECTRUM_MEASUREMENT); 2267ac9a364SKalle Valo IL_CMD(C_POWER_TBL); 2277ac9a364SKalle Valo IL_CMD(N_PM_SLEEP); 2287ac9a364SKalle Valo IL_CMD(N_PM_DEBUG_STATS); 2297ac9a364SKalle Valo IL_CMD(C_SCAN); 2307ac9a364SKalle Valo IL_CMD(C_SCAN_ABORT); 2317ac9a364SKalle Valo IL_CMD(N_SCAN_START); 2327ac9a364SKalle Valo IL_CMD(N_SCAN_RESULTS); 2337ac9a364SKalle Valo IL_CMD(N_SCAN_COMPLETE); 2347ac9a364SKalle Valo IL_CMD(N_BEACON); 2357ac9a364SKalle Valo IL_CMD(C_TX_BEACON); 2367ac9a364SKalle Valo IL_CMD(C_TX_PWR_TBL); 2377ac9a364SKalle Valo IL_CMD(C_BT_CONFIG); 2387ac9a364SKalle Valo IL_CMD(C_STATS); 2397ac9a364SKalle Valo IL_CMD(N_STATS); 2407ac9a364SKalle Valo IL_CMD(N_CARD_STATE); 2417ac9a364SKalle Valo IL_CMD(N_MISSED_BEACONS); 2427ac9a364SKalle Valo IL_CMD(C_CT_KILL_CONFIG); 2437ac9a364SKalle Valo IL_CMD(C_SENSITIVITY); 2447ac9a364SKalle Valo IL_CMD(C_PHY_CALIBRATION); 2457ac9a364SKalle Valo IL_CMD(N_RX_PHY); 2467ac9a364SKalle Valo IL_CMD(N_RX_MPDU); 2477ac9a364SKalle Valo IL_CMD(N_RX); 2487ac9a364SKalle Valo IL_CMD(N_COMPRESSED_BA); 2497ac9a364SKalle Valo default: 2507ac9a364SKalle Valo return "UNKNOWN"; 2517ac9a364SKalle Valo 2527ac9a364SKalle Valo } 2537ac9a364SKalle Valo } 2547ac9a364SKalle Valo EXPORT_SYMBOL(il_get_cmd_string); 2557ac9a364SKalle Valo 2567ac9a364SKalle Valo #define HOST_COMPLETE_TIMEOUT (HZ / 2) 2577ac9a364SKalle Valo 2587ac9a364SKalle Valo static void 2597ac9a364SKalle Valo il_generic_cmd_callback(struct il_priv *il, struct il_device_cmd *cmd, 2607ac9a364SKalle Valo struct il_rx_pkt *pkt) 2617ac9a364SKalle Valo { 2627ac9a364SKalle Valo if (pkt->hdr.flags & IL_CMD_FAILED_MSK) { 2637ac9a364SKalle Valo IL_ERR("Bad return from %s (0x%08X)\n", 2647ac9a364SKalle Valo il_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); 2657ac9a364SKalle Valo return; 2667ac9a364SKalle Valo } 2677ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 2687ac9a364SKalle Valo switch (cmd->hdr.cmd) { 2697ac9a364SKalle Valo case C_TX_LINK_QUALITY_CMD: 2707ac9a364SKalle Valo case C_SENSITIVITY: 2717ac9a364SKalle Valo D_HC_DUMP("back from %s (0x%08X)\n", 2727ac9a364SKalle Valo il_get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); 2737ac9a364SKalle Valo break; 2747ac9a364SKalle Valo default: 2757ac9a364SKalle Valo D_HC("back from %s (0x%08X)\n", il_get_cmd_string(cmd->hdr.cmd), 2767ac9a364SKalle Valo pkt->hdr.flags); 2777ac9a364SKalle Valo } 2787ac9a364SKalle Valo #endif 2797ac9a364SKalle Valo } 2807ac9a364SKalle Valo 2817ac9a364SKalle Valo static int 2827ac9a364SKalle Valo il_send_cmd_async(struct il_priv *il, struct il_host_cmd *cmd) 2837ac9a364SKalle Valo { 2847ac9a364SKalle Valo int ret; 2857ac9a364SKalle Valo 2867ac9a364SKalle Valo BUG_ON(!(cmd->flags & CMD_ASYNC)); 2877ac9a364SKalle Valo 2887ac9a364SKalle Valo /* An asynchronous command can not expect an SKB to be set. */ 2897ac9a364SKalle Valo BUG_ON(cmd->flags & CMD_WANT_SKB); 2907ac9a364SKalle Valo 2917ac9a364SKalle Valo /* Assign a generic callback if one is not provided */ 2927ac9a364SKalle Valo if (!cmd->callback) 2937ac9a364SKalle Valo cmd->callback = il_generic_cmd_callback; 2947ac9a364SKalle Valo 2957ac9a364SKalle Valo if (test_bit(S_EXIT_PENDING, &il->status)) 2967ac9a364SKalle Valo return -EBUSY; 2977ac9a364SKalle Valo 2987ac9a364SKalle Valo ret = il_enqueue_hcmd(il, cmd); 2997ac9a364SKalle Valo if (ret < 0) { 3007ac9a364SKalle Valo IL_ERR("Error sending %s: enqueue_hcmd failed: %d\n", 3017ac9a364SKalle Valo il_get_cmd_string(cmd->id), ret); 3027ac9a364SKalle Valo return ret; 3037ac9a364SKalle Valo } 3047ac9a364SKalle Valo return 0; 3057ac9a364SKalle Valo } 3067ac9a364SKalle Valo 3077ac9a364SKalle Valo int 3087ac9a364SKalle Valo il_send_cmd_sync(struct il_priv *il, struct il_host_cmd *cmd) 3097ac9a364SKalle Valo { 3107ac9a364SKalle Valo int cmd_idx; 3117ac9a364SKalle Valo int ret; 3127ac9a364SKalle Valo 3137ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 3147ac9a364SKalle Valo 3157ac9a364SKalle Valo BUG_ON(cmd->flags & CMD_ASYNC); 3167ac9a364SKalle Valo 3177ac9a364SKalle Valo /* A synchronous command can not have a callback set. */ 3187ac9a364SKalle Valo BUG_ON(cmd->callback); 3197ac9a364SKalle Valo 3207ac9a364SKalle Valo D_INFO("Attempting to send sync command %s\n", 3217ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3227ac9a364SKalle Valo 3237ac9a364SKalle Valo set_bit(S_HCMD_ACTIVE, &il->status); 3247ac9a364SKalle Valo D_INFO("Setting HCMD_ACTIVE for command %s\n", 3257ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3267ac9a364SKalle Valo 3277ac9a364SKalle Valo cmd_idx = il_enqueue_hcmd(il, cmd); 3287ac9a364SKalle Valo if (cmd_idx < 0) { 3297ac9a364SKalle Valo ret = cmd_idx; 3307ac9a364SKalle Valo IL_ERR("Error sending %s: enqueue_hcmd failed: %d\n", 3317ac9a364SKalle Valo il_get_cmd_string(cmd->id), ret); 3327ac9a364SKalle Valo goto out; 3337ac9a364SKalle Valo } 3347ac9a364SKalle Valo 3357ac9a364SKalle Valo ret = wait_event_timeout(il->wait_command_queue, 3367ac9a364SKalle Valo !test_bit(S_HCMD_ACTIVE, &il->status), 3377ac9a364SKalle Valo HOST_COMPLETE_TIMEOUT); 3387ac9a364SKalle Valo if (!ret) { 3397ac9a364SKalle Valo if (test_bit(S_HCMD_ACTIVE, &il->status)) { 3407ac9a364SKalle Valo IL_ERR("Error sending %s: time out after %dms.\n", 3417ac9a364SKalle Valo il_get_cmd_string(cmd->id), 3427ac9a364SKalle Valo jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); 3437ac9a364SKalle Valo 3447ac9a364SKalle Valo clear_bit(S_HCMD_ACTIVE, &il->status); 3457ac9a364SKalle Valo D_INFO("Clearing HCMD_ACTIVE for command %s\n", 3467ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3477ac9a364SKalle Valo ret = -ETIMEDOUT; 3487ac9a364SKalle Valo goto cancel; 3497ac9a364SKalle Valo } 3507ac9a364SKalle Valo } 3517ac9a364SKalle Valo 3527ac9a364SKalle Valo if (test_bit(S_RFKILL, &il->status)) { 3537ac9a364SKalle Valo IL_ERR("Command %s aborted: RF KILL Switch\n", 3547ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3557ac9a364SKalle Valo ret = -ECANCELED; 3567ac9a364SKalle Valo goto fail; 3577ac9a364SKalle Valo } 3587ac9a364SKalle Valo if (test_bit(S_FW_ERROR, &il->status)) { 3597ac9a364SKalle Valo IL_ERR("Command %s failed: FW Error\n", 3607ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3617ac9a364SKalle Valo ret = -EIO; 3627ac9a364SKalle Valo goto fail; 3637ac9a364SKalle Valo } 3647ac9a364SKalle Valo if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { 3657ac9a364SKalle Valo IL_ERR("Error: Response NULL in '%s'\n", 3667ac9a364SKalle Valo il_get_cmd_string(cmd->id)); 3677ac9a364SKalle Valo ret = -EIO; 3687ac9a364SKalle Valo goto cancel; 3697ac9a364SKalle Valo } 3707ac9a364SKalle Valo 3717ac9a364SKalle Valo ret = 0; 3727ac9a364SKalle Valo goto out; 3737ac9a364SKalle Valo 3747ac9a364SKalle Valo cancel: 3757ac9a364SKalle Valo if (cmd->flags & CMD_WANT_SKB) { 3767ac9a364SKalle Valo /* 3777ac9a364SKalle Valo * Cancel the CMD_WANT_SKB flag for the cmd in the 3787ac9a364SKalle Valo * TX cmd queue. Otherwise in case the cmd comes 3797ac9a364SKalle Valo * in later, it will possibly set an invalid 3807ac9a364SKalle Valo * address (cmd->meta.source). 3817ac9a364SKalle Valo */ 3827ac9a364SKalle Valo il->txq[il->cmd_queue].meta[cmd_idx].flags &= ~CMD_WANT_SKB; 3837ac9a364SKalle Valo } 3847ac9a364SKalle Valo fail: 3857ac9a364SKalle Valo if (cmd->reply_page) { 3867ac9a364SKalle Valo il_free_pages(il, cmd->reply_page); 3877ac9a364SKalle Valo cmd->reply_page = 0; 3887ac9a364SKalle Valo } 3897ac9a364SKalle Valo out: 3907ac9a364SKalle Valo return ret; 3917ac9a364SKalle Valo } 3927ac9a364SKalle Valo EXPORT_SYMBOL(il_send_cmd_sync); 3937ac9a364SKalle Valo 3947ac9a364SKalle Valo int 3957ac9a364SKalle Valo il_send_cmd(struct il_priv *il, struct il_host_cmd *cmd) 3967ac9a364SKalle Valo { 3977ac9a364SKalle Valo if (cmd->flags & CMD_ASYNC) 3987ac9a364SKalle Valo return il_send_cmd_async(il, cmd); 3997ac9a364SKalle Valo 4007ac9a364SKalle Valo return il_send_cmd_sync(il, cmd); 4017ac9a364SKalle Valo } 4027ac9a364SKalle Valo EXPORT_SYMBOL(il_send_cmd); 4037ac9a364SKalle Valo 4047ac9a364SKalle Valo int 4057ac9a364SKalle Valo il_send_cmd_pdu(struct il_priv *il, u8 id, u16 len, const void *data) 4067ac9a364SKalle Valo { 4077ac9a364SKalle Valo struct il_host_cmd cmd = { 4087ac9a364SKalle Valo .id = id, 4097ac9a364SKalle Valo .len = len, 4107ac9a364SKalle Valo .data = data, 4117ac9a364SKalle Valo }; 4127ac9a364SKalle Valo 4137ac9a364SKalle Valo return il_send_cmd_sync(il, &cmd); 4147ac9a364SKalle Valo } 4157ac9a364SKalle Valo EXPORT_SYMBOL(il_send_cmd_pdu); 4167ac9a364SKalle Valo 4177ac9a364SKalle Valo int 4187ac9a364SKalle Valo il_send_cmd_pdu_async(struct il_priv *il, u8 id, u16 len, const void *data, 4197ac9a364SKalle Valo void (*callback) (struct il_priv *il, 4207ac9a364SKalle Valo struct il_device_cmd *cmd, 4217ac9a364SKalle Valo struct il_rx_pkt *pkt)) 4227ac9a364SKalle Valo { 4237ac9a364SKalle Valo struct il_host_cmd cmd = { 4247ac9a364SKalle Valo .id = id, 4257ac9a364SKalle Valo .len = len, 4267ac9a364SKalle Valo .data = data, 4277ac9a364SKalle Valo }; 4287ac9a364SKalle Valo 4297ac9a364SKalle Valo cmd.flags |= CMD_ASYNC; 4307ac9a364SKalle Valo cmd.callback = callback; 4317ac9a364SKalle Valo 4327ac9a364SKalle Valo return il_send_cmd_async(il, &cmd); 4337ac9a364SKalle Valo } 4347ac9a364SKalle Valo EXPORT_SYMBOL(il_send_cmd_pdu_async); 4357ac9a364SKalle Valo 4367ac9a364SKalle Valo /* default: IL_LED_BLINK(0) using blinking idx table */ 4377ac9a364SKalle Valo static int led_mode; 4387ac9a364SKalle Valo module_param(led_mode, int, S_IRUGO); 4397ac9a364SKalle Valo MODULE_PARM_DESC(led_mode, 4407ac9a364SKalle Valo "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); 4417ac9a364SKalle Valo 4427ac9a364SKalle Valo /* Throughput OFF time(ms) ON time (ms) 4437ac9a364SKalle Valo * >300 25 25 4447ac9a364SKalle Valo * >200 to 300 40 40 4457ac9a364SKalle Valo * >100 to 200 55 55 4467ac9a364SKalle Valo * >70 to 100 65 65 4477ac9a364SKalle Valo * >50 to 70 75 75 4487ac9a364SKalle Valo * >20 to 50 85 85 4497ac9a364SKalle Valo * >10 to 20 95 95 4507ac9a364SKalle Valo * >5 to 10 110 110 4517ac9a364SKalle Valo * >1 to 5 130 130 4527ac9a364SKalle Valo * >0 to 1 167 167 4537ac9a364SKalle Valo * <=0 SOLID ON 4547ac9a364SKalle Valo */ 4557ac9a364SKalle Valo static const struct ieee80211_tpt_blink il_blink[] = { 4567ac9a364SKalle Valo {.throughput = 0, .blink_time = 334}, 4577ac9a364SKalle Valo {.throughput = 1 * 1024 - 1, .blink_time = 260}, 4587ac9a364SKalle Valo {.throughput = 5 * 1024 - 1, .blink_time = 220}, 4597ac9a364SKalle Valo {.throughput = 10 * 1024 - 1, .blink_time = 190}, 4607ac9a364SKalle Valo {.throughput = 20 * 1024 - 1, .blink_time = 170}, 4617ac9a364SKalle Valo {.throughput = 50 * 1024 - 1, .blink_time = 150}, 4627ac9a364SKalle Valo {.throughput = 70 * 1024 - 1, .blink_time = 130}, 4637ac9a364SKalle Valo {.throughput = 100 * 1024 - 1, .blink_time = 110}, 4647ac9a364SKalle Valo {.throughput = 200 * 1024 - 1, .blink_time = 80}, 4657ac9a364SKalle Valo {.throughput = 300 * 1024 - 1, .blink_time = 50}, 4667ac9a364SKalle Valo }; 4677ac9a364SKalle Valo 4687ac9a364SKalle Valo /* 4697ac9a364SKalle Valo * Adjust led blink rate to compensate on a MAC Clock difference on every HW 4707ac9a364SKalle Valo * Led blink rate analysis showed an average deviation of 0% on 3945, 4717ac9a364SKalle Valo * 5% on 4965 HW. 4727ac9a364SKalle Valo * Need to compensate on the led on/off time per HW according to the deviation 4737ac9a364SKalle Valo * to achieve the desired led frequency 4747ac9a364SKalle Valo * The calculation is: (100-averageDeviation)/100 * blinkTime 4757ac9a364SKalle Valo * For code efficiency the calculation will be: 4767ac9a364SKalle Valo * compensation = (100 - averageDeviation) * 64 / 100 4777ac9a364SKalle Valo * NewBlinkTime = (compensation * BlinkTime) / 64 4787ac9a364SKalle Valo */ 4797ac9a364SKalle Valo static inline u8 4807ac9a364SKalle Valo il_blink_compensation(struct il_priv *il, u8 time, u16 compensation) 4817ac9a364SKalle Valo { 4827ac9a364SKalle Valo if (!compensation) { 4837ac9a364SKalle Valo IL_ERR("undefined blink compensation: " 4847ac9a364SKalle Valo "use pre-defined blinking time\n"); 4857ac9a364SKalle Valo return time; 4867ac9a364SKalle Valo } 4877ac9a364SKalle Valo 4887ac9a364SKalle Valo return (u8) ((time * compensation) >> 6); 4897ac9a364SKalle Valo } 4907ac9a364SKalle Valo 4917ac9a364SKalle Valo /* Set led pattern command */ 4927ac9a364SKalle Valo static int 4937ac9a364SKalle Valo il_led_cmd(struct il_priv *il, unsigned long on, unsigned long off) 4947ac9a364SKalle Valo { 4957ac9a364SKalle Valo struct il_led_cmd led_cmd = { 4967ac9a364SKalle Valo .id = IL_LED_LINK, 4977ac9a364SKalle Valo .interval = IL_DEF_LED_INTRVL 4987ac9a364SKalle Valo }; 4997ac9a364SKalle Valo int ret; 5007ac9a364SKalle Valo 5017ac9a364SKalle Valo if (!test_bit(S_READY, &il->status)) 5027ac9a364SKalle Valo return -EBUSY; 5037ac9a364SKalle Valo 5047ac9a364SKalle Valo if (il->blink_on == on && il->blink_off == off) 5057ac9a364SKalle Valo return 0; 5067ac9a364SKalle Valo 5077ac9a364SKalle Valo if (off == 0) { 5087ac9a364SKalle Valo /* led is SOLID_ON */ 5097ac9a364SKalle Valo on = IL_LED_SOLID; 5107ac9a364SKalle Valo } 5117ac9a364SKalle Valo 5127ac9a364SKalle Valo D_LED("Led blink time compensation=%u\n", 5137ac9a364SKalle Valo il->cfg->led_compensation); 5147ac9a364SKalle Valo led_cmd.on = 5157ac9a364SKalle Valo il_blink_compensation(il, on, 5167ac9a364SKalle Valo il->cfg->led_compensation); 5177ac9a364SKalle Valo led_cmd.off = 5187ac9a364SKalle Valo il_blink_compensation(il, off, 5197ac9a364SKalle Valo il->cfg->led_compensation); 5207ac9a364SKalle Valo 5217ac9a364SKalle Valo ret = il->ops->send_led_cmd(il, &led_cmd); 5227ac9a364SKalle Valo if (!ret) { 5237ac9a364SKalle Valo il->blink_on = on; 5247ac9a364SKalle Valo il->blink_off = off; 5257ac9a364SKalle Valo } 5267ac9a364SKalle Valo return ret; 5277ac9a364SKalle Valo } 5287ac9a364SKalle Valo 5297ac9a364SKalle Valo static void 5307ac9a364SKalle Valo il_led_brightness_set(struct led_classdev *led_cdev, 5317ac9a364SKalle Valo enum led_brightness brightness) 5327ac9a364SKalle Valo { 5337ac9a364SKalle Valo struct il_priv *il = container_of(led_cdev, struct il_priv, led); 5347ac9a364SKalle Valo unsigned long on = 0; 5357ac9a364SKalle Valo 5367ac9a364SKalle Valo if (brightness > 0) 5377ac9a364SKalle Valo on = IL_LED_SOLID; 5387ac9a364SKalle Valo 5397ac9a364SKalle Valo il_led_cmd(il, on, 0); 5407ac9a364SKalle Valo } 5417ac9a364SKalle Valo 5427ac9a364SKalle Valo static int 5437ac9a364SKalle Valo il_led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, 5447ac9a364SKalle Valo unsigned long *delay_off) 5457ac9a364SKalle Valo { 5467ac9a364SKalle Valo struct il_priv *il = container_of(led_cdev, struct il_priv, led); 5477ac9a364SKalle Valo 5487ac9a364SKalle Valo return il_led_cmd(il, *delay_on, *delay_off); 5497ac9a364SKalle Valo } 5507ac9a364SKalle Valo 5517ac9a364SKalle Valo void 5527ac9a364SKalle Valo il_leds_init(struct il_priv *il) 5537ac9a364SKalle Valo { 5547ac9a364SKalle Valo int mode = led_mode; 5557ac9a364SKalle Valo int ret; 5567ac9a364SKalle Valo 5577ac9a364SKalle Valo if (mode == IL_LED_DEFAULT) 5587ac9a364SKalle Valo mode = il->cfg->led_mode; 5597ac9a364SKalle Valo 5607ac9a364SKalle Valo il->led.name = 5617ac9a364SKalle Valo kasprintf(GFP_KERNEL, "%s-led", wiphy_name(il->hw->wiphy)); 5627ac9a364SKalle Valo il->led.brightness_set = il_led_brightness_set; 5637ac9a364SKalle Valo il->led.blink_set = il_led_blink_set; 5647ac9a364SKalle Valo il->led.max_brightness = 1; 5657ac9a364SKalle Valo 5667ac9a364SKalle Valo switch (mode) { 5677ac9a364SKalle Valo case IL_LED_DEFAULT: 5687ac9a364SKalle Valo WARN_ON(1); 5697ac9a364SKalle Valo break; 5707ac9a364SKalle Valo case IL_LED_BLINK: 5717ac9a364SKalle Valo il->led.default_trigger = 5727ac9a364SKalle Valo ieee80211_create_tpt_led_trigger(il->hw, 5737ac9a364SKalle Valo IEEE80211_TPT_LEDTRIG_FL_CONNECTED, 5747ac9a364SKalle Valo il_blink, 5757ac9a364SKalle Valo ARRAY_SIZE(il_blink)); 5767ac9a364SKalle Valo break; 5777ac9a364SKalle Valo case IL_LED_RF_STATE: 5787ac9a364SKalle Valo il->led.default_trigger = ieee80211_get_radio_led_name(il->hw); 5797ac9a364SKalle Valo break; 5807ac9a364SKalle Valo } 5817ac9a364SKalle Valo 5827ac9a364SKalle Valo ret = led_classdev_register(&il->pci_dev->dev, &il->led); 5837ac9a364SKalle Valo if (ret) { 5847ac9a364SKalle Valo kfree(il->led.name); 5857ac9a364SKalle Valo return; 5867ac9a364SKalle Valo } 5877ac9a364SKalle Valo 5887ac9a364SKalle Valo il->led_registered = true; 5897ac9a364SKalle Valo } 5907ac9a364SKalle Valo EXPORT_SYMBOL(il_leds_init); 5917ac9a364SKalle Valo 5927ac9a364SKalle Valo void 5937ac9a364SKalle Valo il_leds_exit(struct il_priv *il) 5947ac9a364SKalle Valo { 5957ac9a364SKalle Valo if (!il->led_registered) 5967ac9a364SKalle Valo return; 5977ac9a364SKalle Valo 5987ac9a364SKalle Valo led_classdev_unregister(&il->led); 5997ac9a364SKalle Valo kfree(il->led.name); 6007ac9a364SKalle Valo } 6017ac9a364SKalle Valo EXPORT_SYMBOL(il_leds_exit); 6027ac9a364SKalle Valo 6037ac9a364SKalle Valo /************************** EEPROM BANDS **************************** 6047ac9a364SKalle Valo * 6057ac9a364SKalle Valo * The il_eeprom_band definitions below provide the mapping from the 6067ac9a364SKalle Valo * EEPROM contents to the specific channel number supported for each 6077ac9a364SKalle Valo * band. 6087ac9a364SKalle Valo * 6097ac9a364SKalle Valo * For example, il_priv->eeprom.band_3_channels[4] from the band_3 6107ac9a364SKalle Valo * definition below maps to physical channel 42 in the 5.2GHz spectrum. 6117ac9a364SKalle Valo * The specific geography and calibration information for that channel 6127ac9a364SKalle Valo * is contained in the eeprom map itself. 6137ac9a364SKalle Valo * 6147ac9a364SKalle Valo * During init, we copy the eeprom information and channel map 6157ac9a364SKalle Valo * information into il->channel_info_24/52 and il->channel_map_24/52 6167ac9a364SKalle Valo * 6177ac9a364SKalle Valo * channel_map_24/52 provides the idx in the channel_info array for a 6187ac9a364SKalle Valo * given channel. We have to have two separate maps as there is channel 6197ac9a364SKalle Valo * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and 6207ac9a364SKalle Valo * band_2 6217ac9a364SKalle Valo * 6227ac9a364SKalle Valo * A value of 0xff stored in the channel_map indicates that the channel 6237ac9a364SKalle Valo * is not supported by the hardware at all. 6247ac9a364SKalle Valo * 6257ac9a364SKalle Valo * A value of 0xfe in the channel_map indicates that the channel is not 6267ac9a364SKalle Valo * valid for Tx with the current hardware. This means that 6277ac9a364SKalle Valo * while the system can tune and receive on a given channel, it may not 6287ac9a364SKalle Valo * be able to associate or transmit any frames on that 6297ac9a364SKalle Valo * channel. There is no corresponding channel information for that 6307ac9a364SKalle Valo * entry. 6317ac9a364SKalle Valo * 6327ac9a364SKalle Valo *********************************************************************/ 6337ac9a364SKalle Valo 6347ac9a364SKalle Valo /* 2.4 GHz */ 6357ac9a364SKalle Valo const u8 il_eeprom_band_1[14] = { 6367ac9a364SKalle Valo 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 6377ac9a364SKalle Valo }; 6387ac9a364SKalle Valo 6397ac9a364SKalle Valo /* 5.2 GHz bands */ 6407ac9a364SKalle Valo static const u8 il_eeprom_band_2[] = { /* 4915-5080MHz */ 6417ac9a364SKalle Valo 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 6427ac9a364SKalle Valo }; 6437ac9a364SKalle Valo 6447ac9a364SKalle Valo static const u8 il_eeprom_band_3[] = { /* 5170-5320MHz */ 6457ac9a364SKalle Valo 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 6467ac9a364SKalle Valo }; 6477ac9a364SKalle Valo 6487ac9a364SKalle Valo static const u8 il_eeprom_band_4[] = { /* 5500-5700MHz */ 6497ac9a364SKalle Valo 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 6507ac9a364SKalle Valo }; 6517ac9a364SKalle Valo 6527ac9a364SKalle Valo static const u8 il_eeprom_band_5[] = { /* 5725-5825MHz */ 6537ac9a364SKalle Valo 145, 149, 153, 157, 161, 165 6547ac9a364SKalle Valo }; 6557ac9a364SKalle Valo 6567ac9a364SKalle Valo static const u8 il_eeprom_band_6[] = { /* 2.4 ht40 channel */ 6577ac9a364SKalle Valo 1, 2, 3, 4, 5, 6, 7 6587ac9a364SKalle Valo }; 6597ac9a364SKalle Valo 6607ac9a364SKalle Valo static const u8 il_eeprom_band_7[] = { /* 5.2 ht40 channel */ 6617ac9a364SKalle Valo 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 6627ac9a364SKalle Valo }; 6637ac9a364SKalle Valo 6647ac9a364SKalle Valo /****************************************************************************** 6657ac9a364SKalle Valo * 6667ac9a364SKalle Valo * EEPROM related functions 6677ac9a364SKalle Valo * 6687ac9a364SKalle Valo ******************************************************************************/ 6697ac9a364SKalle Valo 6707ac9a364SKalle Valo static int 6717ac9a364SKalle Valo il_eeprom_verify_signature(struct il_priv *il) 6727ac9a364SKalle Valo { 6737ac9a364SKalle Valo u32 gp = _il_rd(il, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; 6747ac9a364SKalle Valo int ret = 0; 6757ac9a364SKalle Valo 6767ac9a364SKalle Valo D_EEPROM("EEPROM signature=0x%08x\n", gp); 6777ac9a364SKalle Valo switch (gp) { 6787ac9a364SKalle Valo case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: 6797ac9a364SKalle Valo case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: 6807ac9a364SKalle Valo break; 6817ac9a364SKalle Valo default: 6827ac9a364SKalle Valo IL_ERR("bad EEPROM signature," "EEPROM_GP=0x%08x\n", gp); 6837ac9a364SKalle Valo ret = -ENOENT; 6847ac9a364SKalle Valo break; 6857ac9a364SKalle Valo } 6867ac9a364SKalle Valo return ret; 6877ac9a364SKalle Valo } 6887ac9a364SKalle Valo 6897ac9a364SKalle Valo const u8 * 6907ac9a364SKalle Valo il_eeprom_query_addr(const struct il_priv *il, size_t offset) 6917ac9a364SKalle Valo { 6927ac9a364SKalle Valo BUG_ON(offset >= il->cfg->eeprom_size); 6937ac9a364SKalle Valo return &il->eeprom[offset]; 6947ac9a364SKalle Valo } 6957ac9a364SKalle Valo EXPORT_SYMBOL(il_eeprom_query_addr); 6967ac9a364SKalle Valo 6977ac9a364SKalle Valo u16 6987ac9a364SKalle Valo il_eeprom_query16(const struct il_priv *il, size_t offset) 6997ac9a364SKalle Valo { 7007ac9a364SKalle Valo if (!il->eeprom) 7017ac9a364SKalle Valo return 0; 7027ac9a364SKalle Valo return (u16) il->eeprom[offset] | ((u16) il->eeprom[offset + 1] << 8); 7037ac9a364SKalle Valo } 7047ac9a364SKalle Valo EXPORT_SYMBOL(il_eeprom_query16); 7057ac9a364SKalle Valo 7067ac9a364SKalle Valo /** 7077ac9a364SKalle Valo * il_eeprom_init - read EEPROM contents 7087ac9a364SKalle Valo * 7097ac9a364SKalle Valo * Load the EEPROM contents from adapter into il->eeprom 7107ac9a364SKalle Valo * 7117ac9a364SKalle Valo * NOTE: This routine uses the non-debug IO access functions. 7127ac9a364SKalle Valo */ 7137ac9a364SKalle Valo int 7147ac9a364SKalle Valo il_eeprom_init(struct il_priv *il) 7157ac9a364SKalle Valo { 7167ac9a364SKalle Valo __le16 *e; 7177ac9a364SKalle Valo u32 gp = _il_rd(il, CSR_EEPROM_GP); 7187ac9a364SKalle Valo int sz; 7197ac9a364SKalle Valo int ret; 7207ac9a364SKalle Valo u16 addr; 7217ac9a364SKalle Valo 7227ac9a364SKalle Valo /* allocate eeprom */ 7237ac9a364SKalle Valo sz = il->cfg->eeprom_size; 7247ac9a364SKalle Valo D_EEPROM("NVM size = %d\n", sz); 7257ac9a364SKalle Valo il->eeprom = kzalloc(sz, GFP_KERNEL); 7267ac9a364SKalle Valo if (!il->eeprom) { 7277ac9a364SKalle Valo ret = -ENOMEM; 7287ac9a364SKalle Valo goto alloc_err; 7297ac9a364SKalle Valo } 7307ac9a364SKalle Valo e = (__le16 *) il->eeprom; 7317ac9a364SKalle Valo 7327ac9a364SKalle Valo il->ops->apm_init(il); 7337ac9a364SKalle Valo 7347ac9a364SKalle Valo ret = il_eeprom_verify_signature(il); 7357ac9a364SKalle Valo if (ret < 0) { 7367ac9a364SKalle Valo IL_ERR("EEPROM not found, EEPROM_GP=0x%08x\n", gp); 7377ac9a364SKalle Valo ret = -ENOENT; 7387ac9a364SKalle Valo goto err; 7397ac9a364SKalle Valo } 7407ac9a364SKalle Valo 7417ac9a364SKalle Valo /* Make sure driver (instead of uCode) is allowed to read EEPROM */ 7427ac9a364SKalle Valo ret = il->ops->eeprom_acquire_semaphore(il); 7437ac9a364SKalle Valo if (ret < 0) { 7447ac9a364SKalle Valo IL_ERR("Failed to acquire EEPROM semaphore.\n"); 7457ac9a364SKalle Valo ret = -ENOENT; 7467ac9a364SKalle Valo goto err; 7477ac9a364SKalle Valo } 7487ac9a364SKalle Valo 7497ac9a364SKalle Valo /* eeprom is an array of 16bit values */ 7507ac9a364SKalle Valo for (addr = 0; addr < sz; addr += sizeof(u16)) { 7517ac9a364SKalle Valo u32 r; 7527ac9a364SKalle Valo 7537ac9a364SKalle Valo _il_wr(il, CSR_EEPROM_REG, 7547ac9a364SKalle Valo CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); 7557ac9a364SKalle Valo 7567ac9a364SKalle Valo ret = 7577ac9a364SKalle Valo _il_poll_bit(il, CSR_EEPROM_REG, 7587ac9a364SKalle Valo CSR_EEPROM_REG_READ_VALID_MSK, 7597ac9a364SKalle Valo CSR_EEPROM_REG_READ_VALID_MSK, 7607ac9a364SKalle Valo IL_EEPROM_ACCESS_TIMEOUT); 7617ac9a364SKalle Valo if (ret < 0) { 7627ac9a364SKalle Valo IL_ERR("Time out reading EEPROM[%d]\n", addr); 7637ac9a364SKalle Valo goto done; 7647ac9a364SKalle Valo } 7657ac9a364SKalle Valo r = _il_rd(il, CSR_EEPROM_REG); 7667ac9a364SKalle Valo e[addr / 2] = cpu_to_le16(r >> 16); 7677ac9a364SKalle Valo } 7687ac9a364SKalle Valo 7697ac9a364SKalle Valo D_EEPROM("NVM Type: %s, version: 0x%x\n", "EEPROM", 7707ac9a364SKalle Valo il_eeprom_query16(il, EEPROM_VERSION)); 7717ac9a364SKalle Valo 7727ac9a364SKalle Valo ret = 0; 7737ac9a364SKalle Valo done: 7747ac9a364SKalle Valo il->ops->eeprom_release_semaphore(il); 7757ac9a364SKalle Valo 7767ac9a364SKalle Valo err: 7777ac9a364SKalle Valo if (ret) 7787ac9a364SKalle Valo il_eeprom_free(il); 7797ac9a364SKalle Valo /* Reset chip to save power until we load uCode during "up". */ 7807ac9a364SKalle Valo il_apm_stop(il); 7817ac9a364SKalle Valo alloc_err: 7827ac9a364SKalle Valo return ret; 7837ac9a364SKalle Valo } 7847ac9a364SKalle Valo EXPORT_SYMBOL(il_eeprom_init); 7857ac9a364SKalle Valo 7867ac9a364SKalle Valo void 7877ac9a364SKalle Valo il_eeprom_free(struct il_priv *il) 7887ac9a364SKalle Valo { 7897ac9a364SKalle Valo kfree(il->eeprom); 7907ac9a364SKalle Valo il->eeprom = NULL; 7917ac9a364SKalle Valo } 7927ac9a364SKalle Valo EXPORT_SYMBOL(il_eeprom_free); 7937ac9a364SKalle Valo 7947ac9a364SKalle Valo static void 7957ac9a364SKalle Valo il_init_band_reference(const struct il_priv *il, int eep_band, 7967ac9a364SKalle Valo int *eeprom_ch_count, 7977ac9a364SKalle Valo const struct il_eeprom_channel **eeprom_ch_info, 7987ac9a364SKalle Valo const u8 **eeprom_ch_idx) 7997ac9a364SKalle Valo { 8007ac9a364SKalle Valo u32 offset = il->cfg->regulatory_bands[eep_band - 1]; 8017ac9a364SKalle Valo 8027ac9a364SKalle Valo switch (eep_band) { 8037ac9a364SKalle Valo case 1: /* 2.4GHz band */ 8047ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_1); 8057ac9a364SKalle Valo *eeprom_ch_info = 8067ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8077ac9a364SKalle Valo offset); 8087ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_1; 8097ac9a364SKalle Valo break; 8107ac9a364SKalle Valo case 2: /* 4.9GHz band */ 8117ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_2); 8127ac9a364SKalle Valo *eeprom_ch_info = 8137ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8147ac9a364SKalle Valo offset); 8157ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_2; 8167ac9a364SKalle Valo break; 8177ac9a364SKalle Valo case 3: /* 5.2GHz band */ 8187ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_3); 8197ac9a364SKalle Valo *eeprom_ch_info = 8207ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8217ac9a364SKalle Valo offset); 8227ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_3; 8237ac9a364SKalle Valo break; 8247ac9a364SKalle Valo case 4: /* 5.5GHz band */ 8257ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_4); 8267ac9a364SKalle Valo *eeprom_ch_info = 8277ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8287ac9a364SKalle Valo offset); 8297ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_4; 8307ac9a364SKalle Valo break; 8317ac9a364SKalle Valo case 5: /* 5.7GHz band */ 8327ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_5); 8337ac9a364SKalle Valo *eeprom_ch_info = 8347ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8357ac9a364SKalle Valo offset); 8367ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_5; 8377ac9a364SKalle Valo break; 8387ac9a364SKalle Valo case 6: /* 2.4GHz ht40 channels */ 8397ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_6); 8407ac9a364SKalle Valo *eeprom_ch_info = 8417ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8427ac9a364SKalle Valo offset); 8437ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_6; 8447ac9a364SKalle Valo break; 8457ac9a364SKalle Valo case 7: /* 5 GHz ht40 channels */ 8467ac9a364SKalle Valo *eeprom_ch_count = ARRAY_SIZE(il_eeprom_band_7); 8477ac9a364SKalle Valo *eeprom_ch_info = 8487ac9a364SKalle Valo (struct il_eeprom_channel *)il_eeprom_query_addr(il, 8497ac9a364SKalle Valo offset); 8507ac9a364SKalle Valo *eeprom_ch_idx = il_eeprom_band_7; 8517ac9a364SKalle Valo break; 8527ac9a364SKalle Valo default: 8537ac9a364SKalle Valo BUG(); 8547ac9a364SKalle Valo } 8557ac9a364SKalle Valo } 8567ac9a364SKalle Valo 8577ac9a364SKalle Valo #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ 8587ac9a364SKalle Valo ? # x " " : "") 8597ac9a364SKalle Valo /** 8607ac9a364SKalle Valo * il_mod_ht40_chan_info - Copy ht40 channel info into driver's il. 8617ac9a364SKalle Valo * 8627ac9a364SKalle Valo * Does not set up a command, or touch hardware. 8637ac9a364SKalle Valo */ 8647ac9a364SKalle Valo static int 8657ac9a364SKalle Valo il_mod_ht40_chan_info(struct il_priv *il, enum ieee80211_band band, u16 channel, 8667ac9a364SKalle Valo const struct il_eeprom_channel *eeprom_ch, 8677ac9a364SKalle Valo u8 clear_ht40_extension_channel) 8687ac9a364SKalle Valo { 8697ac9a364SKalle Valo struct il_channel_info *ch_info; 8707ac9a364SKalle Valo 8717ac9a364SKalle Valo ch_info = 8727ac9a364SKalle Valo (struct il_channel_info *)il_get_channel_info(il, band, channel); 8737ac9a364SKalle Valo 8747ac9a364SKalle Valo if (!il_is_channel_valid(ch_info)) 8757ac9a364SKalle Valo return -1; 8767ac9a364SKalle Valo 8777ac9a364SKalle Valo D_EEPROM("HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" 8787ac9a364SKalle Valo " Ad-Hoc %ssupported\n", ch_info->channel, 8797ac9a364SKalle Valo il_is_channel_a_band(ch_info) ? "5.2" : "2.4", 8807ac9a364SKalle Valo CHECK_AND_PRINT(IBSS), CHECK_AND_PRINT(ACTIVE), 8817ac9a364SKalle Valo CHECK_AND_PRINT(RADAR), CHECK_AND_PRINT(WIDE), 8827ac9a364SKalle Valo CHECK_AND_PRINT(DFS), eeprom_ch->flags, 8837ac9a364SKalle Valo eeprom_ch->max_power_avg, 8847ac9a364SKalle Valo ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) && 8857ac9a364SKalle Valo !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); 8867ac9a364SKalle Valo 8877ac9a364SKalle Valo ch_info->ht40_eeprom = *eeprom_ch; 8887ac9a364SKalle Valo ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; 8897ac9a364SKalle Valo ch_info->ht40_flags = eeprom_ch->flags; 8907ac9a364SKalle Valo if (eeprom_ch->flags & EEPROM_CHANNEL_VALID) 8917ac9a364SKalle Valo ch_info->ht40_extension_channel &= 8927ac9a364SKalle Valo ~clear_ht40_extension_channel; 8937ac9a364SKalle Valo 8947ac9a364SKalle Valo return 0; 8957ac9a364SKalle Valo } 8967ac9a364SKalle Valo 8977ac9a364SKalle Valo #define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ 8987ac9a364SKalle Valo ? # x " " : "") 8997ac9a364SKalle Valo 9007ac9a364SKalle Valo /** 9017ac9a364SKalle Valo * il_init_channel_map - Set up driver's info for all possible channels 9027ac9a364SKalle Valo */ 9037ac9a364SKalle Valo int 9047ac9a364SKalle Valo il_init_channel_map(struct il_priv *il) 9057ac9a364SKalle Valo { 9067ac9a364SKalle Valo int eeprom_ch_count = 0; 9077ac9a364SKalle Valo const u8 *eeprom_ch_idx = NULL; 9087ac9a364SKalle Valo const struct il_eeprom_channel *eeprom_ch_info = NULL; 9097ac9a364SKalle Valo int band, ch; 9107ac9a364SKalle Valo struct il_channel_info *ch_info; 9117ac9a364SKalle Valo 9127ac9a364SKalle Valo if (il->channel_count) { 9137ac9a364SKalle Valo D_EEPROM("Channel map already initialized.\n"); 9147ac9a364SKalle Valo return 0; 9157ac9a364SKalle Valo } 9167ac9a364SKalle Valo 9177ac9a364SKalle Valo D_EEPROM("Initializing regulatory info from EEPROM\n"); 9187ac9a364SKalle Valo 9197ac9a364SKalle Valo il->channel_count = 9207ac9a364SKalle Valo ARRAY_SIZE(il_eeprom_band_1) + ARRAY_SIZE(il_eeprom_band_2) + 9217ac9a364SKalle Valo ARRAY_SIZE(il_eeprom_band_3) + ARRAY_SIZE(il_eeprom_band_4) + 9227ac9a364SKalle Valo ARRAY_SIZE(il_eeprom_band_5); 9237ac9a364SKalle Valo 9247ac9a364SKalle Valo D_EEPROM("Parsing data for %d channels.\n", il->channel_count); 9257ac9a364SKalle Valo 9267ac9a364SKalle Valo il->channel_info = 9277ac9a364SKalle Valo kzalloc(sizeof(struct il_channel_info) * il->channel_count, 9287ac9a364SKalle Valo GFP_KERNEL); 9297ac9a364SKalle Valo if (!il->channel_info) { 9307ac9a364SKalle Valo IL_ERR("Could not allocate channel_info\n"); 9317ac9a364SKalle Valo il->channel_count = 0; 9327ac9a364SKalle Valo return -ENOMEM; 9337ac9a364SKalle Valo } 9347ac9a364SKalle Valo 9357ac9a364SKalle Valo ch_info = il->channel_info; 9367ac9a364SKalle Valo 9377ac9a364SKalle Valo /* Loop through the 5 EEPROM bands adding them in order to the 9387ac9a364SKalle Valo * channel map we maintain (that contains additional information than 9397ac9a364SKalle Valo * what just in the EEPROM) */ 9407ac9a364SKalle Valo for (band = 1; band <= 5; band++) { 9417ac9a364SKalle Valo 9427ac9a364SKalle Valo il_init_band_reference(il, band, &eeprom_ch_count, 9437ac9a364SKalle Valo &eeprom_ch_info, &eeprom_ch_idx); 9447ac9a364SKalle Valo 9457ac9a364SKalle Valo /* Loop through each band adding each of the channels */ 9467ac9a364SKalle Valo for (ch = 0; ch < eeprom_ch_count; ch++) { 9477ac9a364SKalle Valo ch_info->channel = eeprom_ch_idx[ch]; 9487ac9a364SKalle Valo ch_info->band = 9497ac9a364SKalle Valo (band == 9507ac9a364SKalle Valo 1) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; 9517ac9a364SKalle Valo 9527ac9a364SKalle Valo /* permanently store EEPROM's channel regulatory flags 9537ac9a364SKalle Valo * and max power in channel info database. */ 9547ac9a364SKalle Valo ch_info->eeprom = eeprom_ch_info[ch]; 9557ac9a364SKalle Valo 9567ac9a364SKalle Valo /* Copy the run-time flags so they are there even on 9577ac9a364SKalle Valo * invalid channels */ 9587ac9a364SKalle Valo ch_info->flags = eeprom_ch_info[ch].flags; 9597ac9a364SKalle Valo /* First write that ht40 is not enabled, and then enable 9607ac9a364SKalle Valo * one by one */ 9617ac9a364SKalle Valo ch_info->ht40_extension_channel = 9627ac9a364SKalle Valo IEEE80211_CHAN_NO_HT40; 9637ac9a364SKalle Valo 9647ac9a364SKalle Valo if (!(il_is_channel_valid(ch_info))) { 9657ac9a364SKalle Valo D_EEPROM("Ch. %d Flags %x [%sGHz] - " 9667ac9a364SKalle Valo "No traffic\n", ch_info->channel, 9677ac9a364SKalle Valo ch_info->flags, 9687ac9a364SKalle Valo il_is_channel_a_band(ch_info) ? "5.2" : 9697ac9a364SKalle Valo "2.4"); 9707ac9a364SKalle Valo ch_info++; 9717ac9a364SKalle Valo continue; 9727ac9a364SKalle Valo } 9737ac9a364SKalle Valo 9747ac9a364SKalle Valo /* Initialize regulatory-based run-time data */ 9757ac9a364SKalle Valo ch_info->max_power_avg = ch_info->curr_txpow = 9767ac9a364SKalle Valo eeprom_ch_info[ch].max_power_avg; 9777ac9a364SKalle Valo ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; 9787ac9a364SKalle Valo ch_info->min_power = 0; 9797ac9a364SKalle Valo 9807ac9a364SKalle Valo D_EEPROM("Ch. %d [%sGHz] " "%s%s%s%s%s%s(0x%02x %ddBm):" 9817ac9a364SKalle Valo " Ad-Hoc %ssupported\n", ch_info->channel, 9827ac9a364SKalle Valo il_is_channel_a_band(ch_info) ? "5.2" : "2.4", 9837ac9a364SKalle Valo CHECK_AND_PRINT_I(VALID), 9847ac9a364SKalle Valo CHECK_AND_PRINT_I(IBSS), 9857ac9a364SKalle Valo CHECK_AND_PRINT_I(ACTIVE), 9867ac9a364SKalle Valo CHECK_AND_PRINT_I(RADAR), 9877ac9a364SKalle Valo CHECK_AND_PRINT_I(WIDE), 9887ac9a364SKalle Valo CHECK_AND_PRINT_I(DFS), 9897ac9a364SKalle Valo eeprom_ch_info[ch].flags, 9907ac9a364SKalle Valo eeprom_ch_info[ch].max_power_avg, 9917ac9a364SKalle Valo ((eeprom_ch_info[ch]. 9927ac9a364SKalle Valo flags & EEPROM_CHANNEL_IBSS) && 9937ac9a364SKalle Valo !(eeprom_ch_info[ch]. 9947ac9a364SKalle Valo flags & EEPROM_CHANNEL_RADAR)) ? "" : 9957ac9a364SKalle Valo "not "); 9967ac9a364SKalle Valo 9977ac9a364SKalle Valo ch_info++; 9987ac9a364SKalle Valo } 9997ac9a364SKalle Valo } 10007ac9a364SKalle Valo 10017ac9a364SKalle Valo /* Check if we do have HT40 channels */ 10027ac9a364SKalle Valo if (il->cfg->regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 && 10037ac9a364SKalle Valo il->cfg->regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40) 10047ac9a364SKalle Valo return 0; 10057ac9a364SKalle Valo 10067ac9a364SKalle Valo /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ 10077ac9a364SKalle Valo for (band = 6; band <= 7; band++) { 10087ac9a364SKalle Valo enum ieee80211_band ieeeband; 10097ac9a364SKalle Valo 10107ac9a364SKalle Valo il_init_band_reference(il, band, &eeprom_ch_count, 10117ac9a364SKalle Valo &eeprom_ch_info, &eeprom_ch_idx); 10127ac9a364SKalle Valo 10137ac9a364SKalle Valo /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ 10147ac9a364SKalle Valo ieeeband = 10157ac9a364SKalle Valo (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; 10167ac9a364SKalle Valo 10177ac9a364SKalle Valo /* Loop through each band adding each of the channels */ 10187ac9a364SKalle Valo for (ch = 0; ch < eeprom_ch_count; ch++) { 10197ac9a364SKalle Valo /* Set up driver's info for lower half */ 10207ac9a364SKalle Valo il_mod_ht40_chan_info(il, ieeeband, eeprom_ch_idx[ch], 10217ac9a364SKalle Valo &eeprom_ch_info[ch], 10227ac9a364SKalle Valo IEEE80211_CHAN_NO_HT40PLUS); 10237ac9a364SKalle Valo 10247ac9a364SKalle Valo /* Set up driver's info for upper half */ 10257ac9a364SKalle Valo il_mod_ht40_chan_info(il, ieeeband, 10267ac9a364SKalle Valo eeprom_ch_idx[ch] + 4, 10277ac9a364SKalle Valo &eeprom_ch_info[ch], 10287ac9a364SKalle Valo IEEE80211_CHAN_NO_HT40MINUS); 10297ac9a364SKalle Valo } 10307ac9a364SKalle Valo } 10317ac9a364SKalle Valo 10327ac9a364SKalle Valo return 0; 10337ac9a364SKalle Valo } 10347ac9a364SKalle Valo EXPORT_SYMBOL(il_init_channel_map); 10357ac9a364SKalle Valo 10367ac9a364SKalle Valo /* 10377ac9a364SKalle Valo * il_free_channel_map - undo allocations in il_init_channel_map 10387ac9a364SKalle Valo */ 10397ac9a364SKalle Valo void 10407ac9a364SKalle Valo il_free_channel_map(struct il_priv *il) 10417ac9a364SKalle Valo { 10427ac9a364SKalle Valo kfree(il->channel_info); 10437ac9a364SKalle Valo il->channel_count = 0; 10447ac9a364SKalle Valo } 10457ac9a364SKalle Valo EXPORT_SYMBOL(il_free_channel_map); 10467ac9a364SKalle Valo 10477ac9a364SKalle Valo /** 10487ac9a364SKalle Valo * il_get_channel_info - Find driver's ilate channel info 10497ac9a364SKalle Valo * 10507ac9a364SKalle Valo * Based on band and channel number. 10517ac9a364SKalle Valo */ 10527ac9a364SKalle Valo const struct il_channel_info * 10537ac9a364SKalle Valo il_get_channel_info(const struct il_priv *il, enum ieee80211_band band, 10547ac9a364SKalle Valo u16 channel) 10557ac9a364SKalle Valo { 10567ac9a364SKalle Valo int i; 10577ac9a364SKalle Valo 10587ac9a364SKalle Valo switch (band) { 10597ac9a364SKalle Valo case IEEE80211_BAND_5GHZ: 10607ac9a364SKalle Valo for (i = 14; i < il->channel_count; i++) { 10617ac9a364SKalle Valo if (il->channel_info[i].channel == channel) 10627ac9a364SKalle Valo return &il->channel_info[i]; 10637ac9a364SKalle Valo } 10647ac9a364SKalle Valo break; 10657ac9a364SKalle Valo case IEEE80211_BAND_2GHZ: 10667ac9a364SKalle Valo if (channel >= 1 && channel <= 14) 10677ac9a364SKalle Valo return &il->channel_info[channel - 1]; 10687ac9a364SKalle Valo break; 10697ac9a364SKalle Valo default: 10707ac9a364SKalle Valo BUG(); 10717ac9a364SKalle Valo } 10727ac9a364SKalle Valo 10737ac9a364SKalle Valo return NULL; 10747ac9a364SKalle Valo } 10757ac9a364SKalle Valo EXPORT_SYMBOL(il_get_channel_info); 10767ac9a364SKalle Valo 10777ac9a364SKalle Valo /* 10787ac9a364SKalle Valo * Setting power level allows the card to go to sleep when not busy. 10797ac9a364SKalle Valo * 10807ac9a364SKalle Valo * We calculate a sleep command based on the required latency, which 10817ac9a364SKalle Valo * we get from mac80211. 10827ac9a364SKalle Valo */ 10837ac9a364SKalle Valo 10847ac9a364SKalle Valo #define SLP_VEC(X0, X1, X2, X3, X4) { \ 10857ac9a364SKalle Valo cpu_to_le32(X0), \ 10867ac9a364SKalle Valo cpu_to_le32(X1), \ 10877ac9a364SKalle Valo cpu_to_le32(X2), \ 10887ac9a364SKalle Valo cpu_to_le32(X3), \ 10897ac9a364SKalle Valo cpu_to_le32(X4) \ 10907ac9a364SKalle Valo } 10917ac9a364SKalle Valo 10927ac9a364SKalle Valo static void 10937ac9a364SKalle Valo il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) 10947ac9a364SKalle Valo { 10957ac9a364SKalle Valo const __le32 interval[3][IL_POWER_VEC_SIZE] = { 10967ac9a364SKalle Valo SLP_VEC(2, 2, 4, 6, 0xFF), 10977ac9a364SKalle Valo SLP_VEC(2, 4, 7, 10, 10), 10987ac9a364SKalle Valo SLP_VEC(4, 7, 10, 10, 0xFF) 10997ac9a364SKalle Valo }; 11007ac9a364SKalle Valo int i, dtim_period, no_dtim; 11017ac9a364SKalle Valo u32 max_sleep; 11027ac9a364SKalle Valo bool skip; 11037ac9a364SKalle Valo 11047ac9a364SKalle Valo memset(cmd, 0, sizeof(*cmd)); 11057ac9a364SKalle Valo 11067ac9a364SKalle Valo if (il->power_data.pci_pm) 11077ac9a364SKalle Valo cmd->flags |= IL_POWER_PCI_PM_MSK; 11087ac9a364SKalle Valo 11097ac9a364SKalle Valo /* if no Power Save, we are done */ 11107ac9a364SKalle Valo if (il->power_data.ps_disabled) 11117ac9a364SKalle Valo return; 11127ac9a364SKalle Valo 11137ac9a364SKalle Valo cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK; 11147ac9a364SKalle Valo cmd->keep_alive_seconds = 0; 11157ac9a364SKalle Valo cmd->debug_flags = 0; 11167ac9a364SKalle Valo cmd->rx_data_timeout = cpu_to_le32(25 * 1024); 11177ac9a364SKalle Valo cmd->tx_data_timeout = cpu_to_le32(25 * 1024); 11187ac9a364SKalle Valo cmd->keep_alive_beacons = 0; 11197ac9a364SKalle Valo 11207ac9a364SKalle Valo dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0; 11217ac9a364SKalle Valo 11227ac9a364SKalle Valo if (dtim_period <= 2) { 11237ac9a364SKalle Valo memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0])); 11247ac9a364SKalle Valo no_dtim = 2; 11257ac9a364SKalle Valo } else if (dtim_period <= 10) { 11267ac9a364SKalle Valo memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1])); 11277ac9a364SKalle Valo no_dtim = 2; 11287ac9a364SKalle Valo } else { 11297ac9a364SKalle Valo memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2])); 11307ac9a364SKalle Valo no_dtim = 0; 11317ac9a364SKalle Valo } 11327ac9a364SKalle Valo 11337ac9a364SKalle Valo if (dtim_period == 0) { 11347ac9a364SKalle Valo dtim_period = 1; 11357ac9a364SKalle Valo skip = false; 11367ac9a364SKalle Valo } else { 11377ac9a364SKalle Valo skip = !!no_dtim; 11387ac9a364SKalle Valo } 11397ac9a364SKalle Valo 11407ac9a364SKalle Valo if (skip) { 11417ac9a364SKalle Valo __le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1]; 11427ac9a364SKalle Valo 11437ac9a364SKalle Valo max_sleep = le32_to_cpu(tmp); 11447ac9a364SKalle Valo if (max_sleep == 0xFF) 11457ac9a364SKalle Valo max_sleep = dtim_period * (skip + 1); 11467ac9a364SKalle Valo else if (max_sleep > dtim_period) 11477ac9a364SKalle Valo max_sleep = (max_sleep / dtim_period) * dtim_period; 11487ac9a364SKalle Valo cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK; 11497ac9a364SKalle Valo } else { 11507ac9a364SKalle Valo max_sleep = dtim_period; 11517ac9a364SKalle Valo cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK; 11527ac9a364SKalle Valo } 11537ac9a364SKalle Valo 11547ac9a364SKalle Valo for (i = 0; i < IL_POWER_VEC_SIZE; i++) 11557ac9a364SKalle Valo if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) 11567ac9a364SKalle Valo cmd->sleep_interval[i] = cpu_to_le32(max_sleep); 11577ac9a364SKalle Valo } 11587ac9a364SKalle Valo 11597ac9a364SKalle Valo static int 11607ac9a364SKalle Valo il_set_power(struct il_priv *il, struct il_powertable_cmd *cmd) 11617ac9a364SKalle Valo { 11627ac9a364SKalle Valo D_POWER("Sending power/sleep command\n"); 11637ac9a364SKalle Valo D_POWER("Flags value = 0x%08X\n", cmd->flags); 11647ac9a364SKalle Valo D_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); 11657ac9a364SKalle Valo D_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); 11667ac9a364SKalle Valo D_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", 11677ac9a364SKalle Valo le32_to_cpu(cmd->sleep_interval[0]), 11687ac9a364SKalle Valo le32_to_cpu(cmd->sleep_interval[1]), 11697ac9a364SKalle Valo le32_to_cpu(cmd->sleep_interval[2]), 11707ac9a364SKalle Valo le32_to_cpu(cmd->sleep_interval[3]), 11717ac9a364SKalle Valo le32_to_cpu(cmd->sleep_interval[4])); 11727ac9a364SKalle Valo 11737ac9a364SKalle Valo return il_send_cmd_pdu(il, C_POWER_TBL, 11747ac9a364SKalle Valo sizeof(struct il_powertable_cmd), cmd); 11757ac9a364SKalle Valo } 11767ac9a364SKalle Valo 11777ac9a364SKalle Valo static int 11787ac9a364SKalle Valo il_power_set_mode(struct il_priv *il, struct il_powertable_cmd *cmd, bool force) 11797ac9a364SKalle Valo { 11807ac9a364SKalle Valo int ret; 11817ac9a364SKalle Valo bool update_chains; 11827ac9a364SKalle Valo 11837ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 11847ac9a364SKalle Valo 11857ac9a364SKalle Valo /* Don't update the RX chain when chain noise calibration is running */ 11867ac9a364SKalle Valo update_chains = il->chain_noise_data.state == IL_CHAIN_NOISE_DONE || 11877ac9a364SKalle Valo il->chain_noise_data.state == IL_CHAIN_NOISE_ALIVE; 11887ac9a364SKalle Valo 11897ac9a364SKalle Valo if (!memcmp(&il->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) 11907ac9a364SKalle Valo return 0; 11917ac9a364SKalle Valo 11927ac9a364SKalle Valo if (!il_is_ready_rf(il)) 11937ac9a364SKalle Valo return -EIO; 11947ac9a364SKalle Valo 11957ac9a364SKalle Valo /* scan complete use sleep_power_next, need to be updated */ 11967ac9a364SKalle Valo memcpy(&il->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); 11977ac9a364SKalle Valo if (test_bit(S_SCANNING, &il->status) && !force) { 11987ac9a364SKalle Valo D_INFO("Defer power set mode while scanning\n"); 11997ac9a364SKalle Valo return 0; 12007ac9a364SKalle Valo } 12017ac9a364SKalle Valo 12027ac9a364SKalle Valo if (cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK) 12037ac9a364SKalle Valo set_bit(S_POWER_PMI, &il->status); 12047ac9a364SKalle Valo 12057ac9a364SKalle Valo ret = il_set_power(il, cmd); 12067ac9a364SKalle Valo if (!ret) { 12077ac9a364SKalle Valo if (!(cmd->flags & IL_POWER_DRIVER_ALLOW_SLEEP_MSK)) 12087ac9a364SKalle Valo clear_bit(S_POWER_PMI, &il->status); 12097ac9a364SKalle Valo 12107ac9a364SKalle Valo if (il->ops->update_chain_flags && update_chains) 12117ac9a364SKalle Valo il->ops->update_chain_flags(il); 12127ac9a364SKalle Valo else if (il->ops->update_chain_flags) 12137ac9a364SKalle Valo D_POWER("Cannot update the power, chain noise " 12147ac9a364SKalle Valo "calibration running: %d\n", 12157ac9a364SKalle Valo il->chain_noise_data.state); 12167ac9a364SKalle Valo 12177ac9a364SKalle Valo memcpy(&il->power_data.sleep_cmd, cmd, sizeof(*cmd)); 12187ac9a364SKalle Valo } else 12197ac9a364SKalle Valo IL_ERR("set power fail, ret = %d", ret); 12207ac9a364SKalle Valo 12217ac9a364SKalle Valo return ret; 12227ac9a364SKalle Valo } 12237ac9a364SKalle Valo 12247ac9a364SKalle Valo int 12257ac9a364SKalle Valo il_power_update_mode(struct il_priv *il, bool force) 12267ac9a364SKalle Valo { 12277ac9a364SKalle Valo struct il_powertable_cmd cmd; 12287ac9a364SKalle Valo 12297ac9a364SKalle Valo il_build_powertable_cmd(il, &cmd); 12307ac9a364SKalle Valo 12317ac9a364SKalle Valo return il_power_set_mode(il, &cmd, force); 12327ac9a364SKalle Valo } 12337ac9a364SKalle Valo EXPORT_SYMBOL(il_power_update_mode); 12347ac9a364SKalle Valo 12357ac9a364SKalle Valo /* initialize to default */ 12367ac9a364SKalle Valo void 12377ac9a364SKalle Valo il_power_initialize(struct il_priv *il) 12387ac9a364SKalle Valo { 12397ac9a364SKalle Valo u16 lctl; 12407ac9a364SKalle Valo 12417ac9a364SKalle Valo pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl); 12427ac9a364SKalle Valo il->power_data.pci_pm = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); 12437ac9a364SKalle Valo 12447ac9a364SKalle Valo il->power_data.debug_sleep_level_override = -1; 12457ac9a364SKalle Valo 12467ac9a364SKalle Valo memset(&il->power_data.sleep_cmd, 0, sizeof(il->power_data.sleep_cmd)); 12477ac9a364SKalle Valo } 12487ac9a364SKalle Valo EXPORT_SYMBOL(il_power_initialize); 12497ac9a364SKalle Valo 12507ac9a364SKalle Valo /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after 12517ac9a364SKalle Valo * sending probe req. This should be set long enough to hear probe responses 12527ac9a364SKalle Valo * from more than one AP. */ 12537ac9a364SKalle Valo #define IL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ 12547ac9a364SKalle Valo #define IL_ACTIVE_DWELL_TIME_52 (20) 12557ac9a364SKalle Valo 12567ac9a364SKalle Valo #define IL_ACTIVE_DWELL_FACTOR_24GHZ (3) 12577ac9a364SKalle Valo #define IL_ACTIVE_DWELL_FACTOR_52GHZ (2) 12587ac9a364SKalle Valo 12597ac9a364SKalle Valo /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. 12607ac9a364SKalle Valo * Must be set longer than active dwell time. 12617ac9a364SKalle Valo * For the most reliable scan, set > AP beacon interval (typically 100msec). */ 12627ac9a364SKalle Valo #define IL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ 12637ac9a364SKalle Valo #define IL_PASSIVE_DWELL_TIME_52 (10) 12647ac9a364SKalle Valo #define IL_PASSIVE_DWELL_BASE (100) 12657ac9a364SKalle Valo #define IL_CHANNEL_TUNE_TIME 5 12667ac9a364SKalle Valo 12677ac9a364SKalle Valo static int 12687ac9a364SKalle Valo il_send_scan_abort(struct il_priv *il) 12697ac9a364SKalle Valo { 12707ac9a364SKalle Valo int ret; 12717ac9a364SKalle Valo struct il_rx_pkt *pkt; 12727ac9a364SKalle Valo struct il_host_cmd cmd = { 12737ac9a364SKalle Valo .id = C_SCAN_ABORT, 12747ac9a364SKalle Valo .flags = CMD_WANT_SKB, 12757ac9a364SKalle Valo }; 12767ac9a364SKalle Valo 12777ac9a364SKalle Valo /* Exit instantly with error when device is not ready 12787ac9a364SKalle Valo * to receive scan abort command or it does not perform 12797ac9a364SKalle Valo * hardware scan currently */ 12807ac9a364SKalle Valo if (!test_bit(S_READY, &il->status) || 12817ac9a364SKalle Valo !test_bit(S_GEO_CONFIGURED, &il->status) || 12827ac9a364SKalle Valo !test_bit(S_SCAN_HW, &il->status) || 12837ac9a364SKalle Valo test_bit(S_FW_ERROR, &il->status) || 12847ac9a364SKalle Valo test_bit(S_EXIT_PENDING, &il->status)) 12857ac9a364SKalle Valo return -EIO; 12867ac9a364SKalle Valo 12877ac9a364SKalle Valo ret = il_send_cmd_sync(il, &cmd); 12887ac9a364SKalle Valo if (ret) 12897ac9a364SKalle Valo return ret; 12907ac9a364SKalle Valo 12917ac9a364SKalle Valo pkt = (struct il_rx_pkt *)cmd.reply_page; 12927ac9a364SKalle Valo if (pkt->u.status != CAN_ABORT_STATUS) { 12937ac9a364SKalle Valo /* The scan abort will return 1 for success or 12947ac9a364SKalle Valo * 2 for "failure". A failure condition can be 12957ac9a364SKalle Valo * due to simply not being in an active scan which 12967ac9a364SKalle Valo * can occur if we send the scan abort before we 12977ac9a364SKalle Valo * the microcode has notified us that a scan is 12987ac9a364SKalle Valo * completed. */ 12997ac9a364SKalle Valo D_SCAN("SCAN_ABORT ret %d.\n", pkt->u.status); 13007ac9a364SKalle Valo ret = -EIO; 13017ac9a364SKalle Valo } 13027ac9a364SKalle Valo 13037ac9a364SKalle Valo il_free_pages(il, cmd.reply_page); 13047ac9a364SKalle Valo return ret; 13057ac9a364SKalle Valo } 13067ac9a364SKalle Valo 13077ac9a364SKalle Valo static void 13087ac9a364SKalle Valo il_complete_scan(struct il_priv *il, bool aborted) 13097ac9a364SKalle Valo { 13107ac9a364SKalle Valo /* check if scan was requested from mac80211 */ 13117ac9a364SKalle Valo if (il->scan_request) { 13127ac9a364SKalle Valo D_SCAN("Complete scan in mac80211\n"); 13137ac9a364SKalle Valo ieee80211_scan_completed(il->hw, aborted); 13147ac9a364SKalle Valo } 13157ac9a364SKalle Valo 13167ac9a364SKalle Valo il->scan_vif = NULL; 13177ac9a364SKalle Valo il->scan_request = NULL; 13187ac9a364SKalle Valo } 13197ac9a364SKalle Valo 13207ac9a364SKalle Valo void 13217ac9a364SKalle Valo il_force_scan_end(struct il_priv *il) 13227ac9a364SKalle Valo { 13237ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 13247ac9a364SKalle Valo 13257ac9a364SKalle Valo if (!test_bit(S_SCANNING, &il->status)) { 13267ac9a364SKalle Valo D_SCAN("Forcing scan end while not scanning\n"); 13277ac9a364SKalle Valo return; 13287ac9a364SKalle Valo } 13297ac9a364SKalle Valo 13307ac9a364SKalle Valo D_SCAN("Forcing scan end\n"); 13317ac9a364SKalle Valo clear_bit(S_SCANNING, &il->status); 13327ac9a364SKalle Valo clear_bit(S_SCAN_HW, &il->status); 13337ac9a364SKalle Valo clear_bit(S_SCAN_ABORTING, &il->status); 13347ac9a364SKalle Valo il_complete_scan(il, true); 13357ac9a364SKalle Valo } 13367ac9a364SKalle Valo 13377ac9a364SKalle Valo static void 13387ac9a364SKalle Valo il_do_scan_abort(struct il_priv *il) 13397ac9a364SKalle Valo { 13407ac9a364SKalle Valo int ret; 13417ac9a364SKalle Valo 13427ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 13437ac9a364SKalle Valo 13447ac9a364SKalle Valo if (!test_bit(S_SCANNING, &il->status)) { 13457ac9a364SKalle Valo D_SCAN("Not performing scan to abort\n"); 13467ac9a364SKalle Valo return; 13477ac9a364SKalle Valo } 13487ac9a364SKalle Valo 13497ac9a364SKalle Valo if (test_and_set_bit(S_SCAN_ABORTING, &il->status)) { 13507ac9a364SKalle Valo D_SCAN("Scan abort in progress\n"); 13517ac9a364SKalle Valo return; 13527ac9a364SKalle Valo } 13537ac9a364SKalle Valo 13547ac9a364SKalle Valo ret = il_send_scan_abort(il); 13557ac9a364SKalle Valo if (ret) { 13567ac9a364SKalle Valo D_SCAN("Send scan abort failed %d\n", ret); 13577ac9a364SKalle Valo il_force_scan_end(il); 13587ac9a364SKalle Valo } else 13597ac9a364SKalle Valo D_SCAN("Successfully send scan abort\n"); 13607ac9a364SKalle Valo } 13617ac9a364SKalle Valo 13627ac9a364SKalle Valo /** 13637ac9a364SKalle Valo * il_scan_cancel - Cancel any currently executing HW scan 13647ac9a364SKalle Valo */ 13657ac9a364SKalle Valo int 13667ac9a364SKalle Valo il_scan_cancel(struct il_priv *il) 13677ac9a364SKalle Valo { 13687ac9a364SKalle Valo D_SCAN("Queuing abort scan\n"); 13697ac9a364SKalle Valo queue_work(il->workqueue, &il->abort_scan); 13707ac9a364SKalle Valo return 0; 13717ac9a364SKalle Valo } 13727ac9a364SKalle Valo EXPORT_SYMBOL(il_scan_cancel); 13737ac9a364SKalle Valo 13747ac9a364SKalle Valo /** 13757ac9a364SKalle Valo * il_scan_cancel_timeout - Cancel any currently executing HW scan 13767ac9a364SKalle Valo * @ms: amount of time to wait (in milliseconds) for scan to abort 13777ac9a364SKalle Valo * 13787ac9a364SKalle Valo */ 13797ac9a364SKalle Valo int 13807ac9a364SKalle Valo il_scan_cancel_timeout(struct il_priv *il, unsigned long ms) 13817ac9a364SKalle Valo { 13827ac9a364SKalle Valo unsigned long timeout = jiffies + msecs_to_jiffies(ms); 13837ac9a364SKalle Valo 13847ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 13857ac9a364SKalle Valo 13867ac9a364SKalle Valo D_SCAN("Scan cancel timeout\n"); 13877ac9a364SKalle Valo 13887ac9a364SKalle Valo il_do_scan_abort(il); 13897ac9a364SKalle Valo 13907ac9a364SKalle Valo while (time_before_eq(jiffies, timeout)) { 13917ac9a364SKalle Valo if (!test_bit(S_SCAN_HW, &il->status)) 13927ac9a364SKalle Valo break; 13937ac9a364SKalle Valo msleep(20); 13947ac9a364SKalle Valo } 13957ac9a364SKalle Valo 13967ac9a364SKalle Valo return test_bit(S_SCAN_HW, &il->status); 13977ac9a364SKalle Valo } 13987ac9a364SKalle Valo EXPORT_SYMBOL(il_scan_cancel_timeout); 13997ac9a364SKalle Valo 14007ac9a364SKalle Valo /* Service response to C_SCAN (0x80) */ 14017ac9a364SKalle Valo static void 14027ac9a364SKalle Valo il_hdl_scan(struct il_priv *il, struct il_rx_buf *rxb) 14037ac9a364SKalle Valo { 14047ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 14057ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 14067ac9a364SKalle Valo struct il_scanreq_notification *notif = 14077ac9a364SKalle Valo (struct il_scanreq_notification *)pkt->u.raw; 14087ac9a364SKalle Valo 14097ac9a364SKalle Valo D_SCAN("Scan request status = 0x%x\n", notif->status); 14107ac9a364SKalle Valo #endif 14117ac9a364SKalle Valo } 14127ac9a364SKalle Valo 14137ac9a364SKalle Valo /* Service N_SCAN_START (0x82) */ 14147ac9a364SKalle Valo static void 14157ac9a364SKalle Valo il_hdl_scan_start(struct il_priv *il, struct il_rx_buf *rxb) 14167ac9a364SKalle Valo { 14177ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 14187ac9a364SKalle Valo struct il_scanstart_notification *notif = 14197ac9a364SKalle Valo (struct il_scanstart_notification *)pkt->u.raw; 14207ac9a364SKalle Valo il->scan_start_tsf = le32_to_cpu(notif->tsf_low); 14217ac9a364SKalle Valo D_SCAN("Scan start: " "%d [802.11%s] " 14227ac9a364SKalle Valo "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", notif->channel, 14237ac9a364SKalle Valo notif->band ? "bg" : "a", le32_to_cpu(notif->tsf_high), 14247ac9a364SKalle Valo le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); 14257ac9a364SKalle Valo } 14267ac9a364SKalle Valo 14277ac9a364SKalle Valo /* Service N_SCAN_RESULTS (0x83) */ 14287ac9a364SKalle Valo static void 14297ac9a364SKalle Valo il_hdl_scan_results(struct il_priv *il, struct il_rx_buf *rxb) 14307ac9a364SKalle Valo { 14317ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 14327ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 14337ac9a364SKalle Valo struct il_scanresults_notification *notif = 14347ac9a364SKalle Valo (struct il_scanresults_notification *)pkt->u.raw; 14357ac9a364SKalle Valo 14367ac9a364SKalle Valo D_SCAN("Scan ch.res: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d " 14377ac9a364SKalle Valo "elapsed=%lu usec\n", notif->channel, notif->band ? "bg" : "a", 14387ac9a364SKalle Valo le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), 14397ac9a364SKalle Valo le32_to_cpu(notif->stats[0]), 14407ac9a364SKalle Valo le32_to_cpu(notif->tsf_low) - il->scan_start_tsf); 14417ac9a364SKalle Valo #endif 14427ac9a364SKalle Valo } 14437ac9a364SKalle Valo 14447ac9a364SKalle Valo /* Service N_SCAN_COMPLETE (0x84) */ 14457ac9a364SKalle Valo static void 14467ac9a364SKalle Valo il_hdl_scan_complete(struct il_priv *il, struct il_rx_buf *rxb) 14477ac9a364SKalle Valo { 14487ac9a364SKalle Valo 14497ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 14507ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 14517ac9a364SKalle Valo struct il_scancomplete_notification *scan_notif = (void *)pkt->u.raw; 14527ac9a364SKalle Valo #endif 14537ac9a364SKalle Valo 14547ac9a364SKalle Valo D_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", 14557ac9a364SKalle Valo scan_notif->scanned_channels, scan_notif->tsf_low, 14567ac9a364SKalle Valo scan_notif->tsf_high, scan_notif->status); 14577ac9a364SKalle Valo 14587ac9a364SKalle Valo /* The HW is no longer scanning */ 14597ac9a364SKalle Valo clear_bit(S_SCAN_HW, &il->status); 14607ac9a364SKalle Valo 14617ac9a364SKalle Valo D_SCAN("Scan on %sGHz took %dms\n", 14627ac9a364SKalle Valo (il->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", 14637ac9a364SKalle Valo jiffies_to_msecs(jiffies - il->scan_start)); 14647ac9a364SKalle Valo 14657ac9a364SKalle Valo queue_work(il->workqueue, &il->scan_completed); 14667ac9a364SKalle Valo } 14677ac9a364SKalle Valo 14687ac9a364SKalle Valo void 14697ac9a364SKalle Valo il_setup_rx_scan_handlers(struct il_priv *il) 14707ac9a364SKalle Valo { 14717ac9a364SKalle Valo /* scan handlers */ 14727ac9a364SKalle Valo il->handlers[C_SCAN] = il_hdl_scan; 14737ac9a364SKalle Valo il->handlers[N_SCAN_START] = il_hdl_scan_start; 14747ac9a364SKalle Valo il->handlers[N_SCAN_RESULTS] = il_hdl_scan_results; 14757ac9a364SKalle Valo il->handlers[N_SCAN_COMPLETE] = il_hdl_scan_complete; 14767ac9a364SKalle Valo } 14777ac9a364SKalle Valo EXPORT_SYMBOL(il_setup_rx_scan_handlers); 14787ac9a364SKalle Valo 14797ac9a364SKalle Valo u16 14807ac9a364SKalle Valo il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band, 14817ac9a364SKalle Valo u8 n_probes) 14827ac9a364SKalle Valo { 14837ac9a364SKalle Valo if (band == IEEE80211_BAND_5GHZ) 14847ac9a364SKalle Valo return IL_ACTIVE_DWELL_TIME_52 + 14857ac9a364SKalle Valo IL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); 14867ac9a364SKalle Valo else 14877ac9a364SKalle Valo return IL_ACTIVE_DWELL_TIME_24 + 14887ac9a364SKalle Valo IL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); 14897ac9a364SKalle Valo } 14907ac9a364SKalle Valo EXPORT_SYMBOL(il_get_active_dwell_time); 14917ac9a364SKalle Valo 14927ac9a364SKalle Valo u16 14937ac9a364SKalle Valo il_get_passive_dwell_time(struct il_priv *il, enum ieee80211_band band, 14947ac9a364SKalle Valo struct ieee80211_vif *vif) 14957ac9a364SKalle Valo { 14967ac9a364SKalle Valo u16 value; 14977ac9a364SKalle Valo 14987ac9a364SKalle Valo u16 passive = 14997ac9a364SKalle Valo (band == 15007ac9a364SKalle Valo IEEE80211_BAND_2GHZ) ? IL_PASSIVE_DWELL_BASE + 15017ac9a364SKalle Valo IL_PASSIVE_DWELL_TIME_24 : IL_PASSIVE_DWELL_BASE + 15027ac9a364SKalle Valo IL_PASSIVE_DWELL_TIME_52; 15037ac9a364SKalle Valo 15047ac9a364SKalle Valo if (il_is_any_associated(il)) { 15057ac9a364SKalle Valo /* 15067ac9a364SKalle Valo * If we're associated, we clamp the maximum passive 15077ac9a364SKalle Valo * dwell time to be 98% of the smallest beacon interval 15087ac9a364SKalle Valo * (minus 2 * channel tune time) 15097ac9a364SKalle Valo */ 15107ac9a364SKalle Valo value = il->vif ? il->vif->bss_conf.beacon_int : 0; 15117ac9a364SKalle Valo if (value > IL_PASSIVE_DWELL_BASE || !value) 15127ac9a364SKalle Valo value = IL_PASSIVE_DWELL_BASE; 15137ac9a364SKalle Valo value = (value * 98) / 100 - IL_CHANNEL_TUNE_TIME * 2; 15147ac9a364SKalle Valo passive = min(value, passive); 15157ac9a364SKalle Valo } 15167ac9a364SKalle Valo 15177ac9a364SKalle Valo return passive; 15187ac9a364SKalle Valo } 15197ac9a364SKalle Valo EXPORT_SYMBOL(il_get_passive_dwell_time); 15207ac9a364SKalle Valo 15217ac9a364SKalle Valo void 15227ac9a364SKalle Valo il_init_scan_params(struct il_priv *il) 15237ac9a364SKalle Valo { 15247ac9a364SKalle Valo u8 ant_idx = fls(il->hw_params.valid_tx_ant) - 1; 15257ac9a364SKalle Valo if (!il->scan_tx_ant[IEEE80211_BAND_5GHZ]) 15267ac9a364SKalle Valo il->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; 15277ac9a364SKalle Valo if (!il->scan_tx_ant[IEEE80211_BAND_2GHZ]) 15287ac9a364SKalle Valo il->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; 15297ac9a364SKalle Valo } 15307ac9a364SKalle Valo EXPORT_SYMBOL(il_init_scan_params); 15317ac9a364SKalle Valo 15327ac9a364SKalle Valo static int 15337ac9a364SKalle Valo il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif) 15347ac9a364SKalle Valo { 15357ac9a364SKalle Valo int ret; 15367ac9a364SKalle Valo 15377ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 15387ac9a364SKalle Valo 15397ac9a364SKalle Valo cancel_delayed_work(&il->scan_check); 15407ac9a364SKalle Valo 15417ac9a364SKalle Valo if (!il_is_ready_rf(il)) { 15427ac9a364SKalle Valo IL_WARN("Request scan called when driver not ready.\n"); 15437ac9a364SKalle Valo return -EIO; 15447ac9a364SKalle Valo } 15457ac9a364SKalle Valo 15467ac9a364SKalle Valo if (test_bit(S_SCAN_HW, &il->status)) { 15477ac9a364SKalle Valo D_SCAN("Multiple concurrent scan requests in parallel.\n"); 15487ac9a364SKalle Valo return -EBUSY; 15497ac9a364SKalle Valo } 15507ac9a364SKalle Valo 15517ac9a364SKalle Valo if (test_bit(S_SCAN_ABORTING, &il->status)) { 15527ac9a364SKalle Valo D_SCAN("Scan request while abort pending.\n"); 15537ac9a364SKalle Valo return -EBUSY; 15547ac9a364SKalle Valo } 15557ac9a364SKalle Valo 15567ac9a364SKalle Valo D_SCAN("Starting scan...\n"); 15577ac9a364SKalle Valo 15587ac9a364SKalle Valo set_bit(S_SCANNING, &il->status); 15597ac9a364SKalle Valo il->scan_start = jiffies; 15607ac9a364SKalle Valo 15617ac9a364SKalle Valo ret = il->ops->request_scan(il, vif); 15627ac9a364SKalle Valo if (ret) { 15637ac9a364SKalle Valo clear_bit(S_SCANNING, &il->status); 15647ac9a364SKalle Valo return ret; 15657ac9a364SKalle Valo } 15667ac9a364SKalle Valo 15677ac9a364SKalle Valo queue_delayed_work(il->workqueue, &il->scan_check, 15687ac9a364SKalle Valo IL_SCAN_CHECK_WATCHDOG); 15697ac9a364SKalle Valo 15707ac9a364SKalle Valo return 0; 15717ac9a364SKalle Valo } 15727ac9a364SKalle Valo 15737ac9a364SKalle Valo int 15747ac9a364SKalle Valo il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15757ac9a364SKalle Valo struct ieee80211_scan_request *hw_req) 15767ac9a364SKalle Valo { 15777ac9a364SKalle Valo struct cfg80211_scan_request *req = &hw_req->req; 15787ac9a364SKalle Valo struct il_priv *il = hw->priv; 15797ac9a364SKalle Valo int ret; 15807ac9a364SKalle Valo 15817ac9a364SKalle Valo if (req->n_channels == 0) { 15827ac9a364SKalle Valo IL_ERR("Can not scan on no channels.\n"); 15837ac9a364SKalle Valo return -EINVAL; 15847ac9a364SKalle Valo } 15857ac9a364SKalle Valo 15867ac9a364SKalle Valo mutex_lock(&il->mutex); 15877ac9a364SKalle Valo D_MAC80211("enter\n"); 15887ac9a364SKalle Valo 15897ac9a364SKalle Valo if (test_bit(S_SCANNING, &il->status)) { 15907ac9a364SKalle Valo D_SCAN("Scan already in progress.\n"); 15917ac9a364SKalle Valo ret = -EAGAIN; 15927ac9a364SKalle Valo goto out_unlock; 15937ac9a364SKalle Valo } 15947ac9a364SKalle Valo 15957ac9a364SKalle Valo /* mac80211 will only ask for one band at a time */ 15967ac9a364SKalle Valo il->scan_request = req; 15977ac9a364SKalle Valo il->scan_vif = vif; 15987ac9a364SKalle Valo il->scan_band = req->channels[0]->band; 15997ac9a364SKalle Valo 16007ac9a364SKalle Valo ret = il_scan_initiate(il, vif); 16017ac9a364SKalle Valo 16027ac9a364SKalle Valo out_unlock: 16037ac9a364SKalle Valo D_MAC80211("leave ret %d\n", ret); 16047ac9a364SKalle Valo mutex_unlock(&il->mutex); 16057ac9a364SKalle Valo 16067ac9a364SKalle Valo return ret; 16077ac9a364SKalle Valo } 16087ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_hw_scan); 16097ac9a364SKalle Valo 16107ac9a364SKalle Valo static void 16117ac9a364SKalle Valo il_bg_scan_check(struct work_struct *data) 16127ac9a364SKalle Valo { 16137ac9a364SKalle Valo struct il_priv *il = 16147ac9a364SKalle Valo container_of(data, struct il_priv, scan_check.work); 16157ac9a364SKalle Valo 16167ac9a364SKalle Valo D_SCAN("Scan check work\n"); 16177ac9a364SKalle Valo 16187ac9a364SKalle Valo /* Since we are here firmware does not finish scan and 16197ac9a364SKalle Valo * most likely is in bad shape, so we don't bother to 16207ac9a364SKalle Valo * send abort command, just force scan complete to mac80211 */ 16217ac9a364SKalle Valo mutex_lock(&il->mutex); 16227ac9a364SKalle Valo il_force_scan_end(il); 16237ac9a364SKalle Valo mutex_unlock(&il->mutex); 16247ac9a364SKalle Valo } 16257ac9a364SKalle Valo 16267ac9a364SKalle Valo /** 16277ac9a364SKalle Valo * il_fill_probe_req - fill in all required fields and IE for probe request 16287ac9a364SKalle Valo */ 16297ac9a364SKalle Valo 16307ac9a364SKalle Valo u16 16317ac9a364SKalle Valo il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, 16327ac9a364SKalle Valo const u8 *ta, const u8 *ies, int ie_len, int left) 16337ac9a364SKalle Valo { 16347ac9a364SKalle Valo int len = 0; 16357ac9a364SKalle Valo u8 *pos = NULL; 16367ac9a364SKalle Valo 16377ac9a364SKalle Valo /* Make sure there is enough space for the probe request, 16387ac9a364SKalle Valo * two mandatory IEs and the data */ 16397ac9a364SKalle Valo left -= 24; 16407ac9a364SKalle Valo if (left < 0) 16417ac9a364SKalle Valo return 0; 16427ac9a364SKalle Valo 16437ac9a364SKalle Valo frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 16447ac9a364SKalle Valo eth_broadcast_addr(frame->da); 16457ac9a364SKalle Valo memcpy(frame->sa, ta, ETH_ALEN); 16467ac9a364SKalle Valo eth_broadcast_addr(frame->bssid); 16477ac9a364SKalle Valo frame->seq_ctrl = 0; 16487ac9a364SKalle Valo 16497ac9a364SKalle Valo len += 24; 16507ac9a364SKalle Valo 16517ac9a364SKalle Valo /* ...next IE... */ 16527ac9a364SKalle Valo pos = &frame->u.probe_req.variable[0]; 16537ac9a364SKalle Valo 16547ac9a364SKalle Valo /* fill in our indirect SSID IE */ 16557ac9a364SKalle Valo left -= 2; 16567ac9a364SKalle Valo if (left < 0) 16577ac9a364SKalle Valo return 0; 16587ac9a364SKalle Valo *pos++ = WLAN_EID_SSID; 16597ac9a364SKalle Valo *pos++ = 0; 16607ac9a364SKalle Valo 16617ac9a364SKalle Valo len += 2; 16627ac9a364SKalle Valo 16637ac9a364SKalle Valo if (WARN_ON(left < ie_len)) 16647ac9a364SKalle Valo return len; 16657ac9a364SKalle Valo 16667ac9a364SKalle Valo if (ies && ie_len) { 16677ac9a364SKalle Valo memcpy(pos, ies, ie_len); 16687ac9a364SKalle Valo len += ie_len; 16697ac9a364SKalle Valo } 16707ac9a364SKalle Valo 16717ac9a364SKalle Valo return (u16) len; 16727ac9a364SKalle Valo } 16737ac9a364SKalle Valo EXPORT_SYMBOL(il_fill_probe_req); 16747ac9a364SKalle Valo 16757ac9a364SKalle Valo static void 16767ac9a364SKalle Valo il_bg_abort_scan(struct work_struct *work) 16777ac9a364SKalle Valo { 16787ac9a364SKalle Valo struct il_priv *il = container_of(work, struct il_priv, abort_scan); 16797ac9a364SKalle Valo 16807ac9a364SKalle Valo D_SCAN("Abort scan work\n"); 16817ac9a364SKalle Valo 16827ac9a364SKalle Valo /* We keep scan_check work queued in case when firmware will not 16837ac9a364SKalle Valo * report back scan completed notification */ 16847ac9a364SKalle Valo mutex_lock(&il->mutex); 16857ac9a364SKalle Valo il_scan_cancel_timeout(il, 200); 16867ac9a364SKalle Valo mutex_unlock(&il->mutex); 16877ac9a364SKalle Valo } 16887ac9a364SKalle Valo 16897ac9a364SKalle Valo static void 16907ac9a364SKalle Valo il_bg_scan_completed(struct work_struct *work) 16917ac9a364SKalle Valo { 16927ac9a364SKalle Valo struct il_priv *il = container_of(work, struct il_priv, scan_completed); 16937ac9a364SKalle Valo bool aborted; 16947ac9a364SKalle Valo 16957ac9a364SKalle Valo D_SCAN("Completed scan.\n"); 16967ac9a364SKalle Valo 16977ac9a364SKalle Valo cancel_delayed_work(&il->scan_check); 16987ac9a364SKalle Valo 16997ac9a364SKalle Valo mutex_lock(&il->mutex); 17007ac9a364SKalle Valo 17017ac9a364SKalle Valo aborted = test_and_clear_bit(S_SCAN_ABORTING, &il->status); 17027ac9a364SKalle Valo if (aborted) 17037ac9a364SKalle Valo D_SCAN("Aborted scan completed.\n"); 17047ac9a364SKalle Valo 17057ac9a364SKalle Valo if (!test_and_clear_bit(S_SCANNING, &il->status)) { 17067ac9a364SKalle Valo D_SCAN("Scan already completed.\n"); 17077ac9a364SKalle Valo goto out_settings; 17087ac9a364SKalle Valo } 17097ac9a364SKalle Valo 17107ac9a364SKalle Valo il_complete_scan(il, aborted); 17117ac9a364SKalle Valo 17127ac9a364SKalle Valo out_settings: 17137ac9a364SKalle Valo /* Can we still talk to firmware ? */ 17147ac9a364SKalle Valo if (!il_is_ready_rf(il)) 17157ac9a364SKalle Valo goto out; 17167ac9a364SKalle Valo 17177ac9a364SKalle Valo /* 17187ac9a364SKalle Valo * We do not commit power settings while scan is pending, 17197ac9a364SKalle Valo * do it now if the settings changed. 17207ac9a364SKalle Valo */ 17217ac9a364SKalle Valo il_power_set_mode(il, &il->power_data.sleep_cmd_next, false); 17227ac9a364SKalle Valo il_set_tx_power(il, il->tx_power_next, false); 17237ac9a364SKalle Valo 17247ac9a364SKalle Valo il->ops->post_scan(il); 17257ac9a364SKalle Valo 17267ac9a364SKalle Valo out: 17277ac9a364SKalle Valo mutex_unlock(&il->mutex); 17287ac9a364SKalle Valo } 17297ac9a364SKalle Valo 17307ac9a364SKalle Valo void 17317ac9a364SKalle Valo il_setup_scan_deferred_work(struct il_priv *il) 17327ac9a364SKalle Valo { 17337ac9a364SKalle Valo INIT_WORK(&il->scan_completed, il_bg_scan_completed); 17347ac9a364SKalle Valo INIT_WORK(&il->abort_scan, il_bg_abort_scan); 17357ac9a364SKalle Valo INIT_DELAYED_WORK(&il->scan_check, il_bg_scan_check); 17367ac9a364SKalle Valo } 17377ac9a364SKalle Valo EXPORT_SYMBOL(il_setup_scan_deferred_work); 17387ac9a364SKalle Valo 17397ac9a364SKalle Valo void 17407ac9a364SKalle Valo il_cancel_scan_deferred_work(struct il_priv *il) 17417ac9a364SKalle Valo { 17427ac9a364SKalle Valo cancel_work_sync(&il->abort_scan); 17437ac9a364SKalle Valo cancel_work_sync(&il->scan_completed); 17447ac9a364SKalle Valo 17457ac9a364SKalle Valo if (cancel_delayed_work_sync(&il->scan_check)) { 17467ac9a364SKalle Valo mutex_lock(&il->mutex); 17477ac9a364SKalle Valo il_force_scan_end(il); 17487ac9a364SKalle Valo mutex_unlock(&il->mutex); 17497ac9a364SKalle Valo } 17507ac9a364SKalle Valo } 17517ac9a364SKalle Valo EXPORT_SYMBOL(il_cancel_scan_deferred_work); 17527ac9a364SKalle Valo 17537ac9a364SKalle Valo /* il->sta_lock must be held */ 17547ac9a364SKalle Valo static void 17557ac9a364SKalle Valo il_sta_ucode_activate(struct il_priv *il, u8 sta_id) 17567ac9a364SKalle Valo { 17577ac9a364SKalle Valo 17587ac9a364SKalle Valo if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE)) 17597ac9a364SKalle Valo IL_ERR("ACTIVATE a non DRIVER active station id %u addr %pM\n", 17607ac9a364SKalle Valo sta_id, il->stations[sta_id].sta.sta.addr); 17617ac9a364SKalle Valo 17627ac9a364SKalle Valo if (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) { 17637ac9a364SKalle Valo D_ASSOC("STA id %u addr %pM already present" 17647ac9a364SKalle Valo " in uCode (according to driver)\n", sta_id, 17657ac9a364SKalle Valo il->stations[sta_id].sta.sta.addr); 17667ac9a364SKalle Valo } else { 17677ac9a364SKalle Valo il->stations[sta_id].used |= IL_STA_UCODE_ACTIVE; 17687ac9a364SKalle Valo D_ASSOC("Added STA id %u addr %pM to uCode\n", sta_id, 17697ac9a364SKalle Valo il->stations[sta_id].sta.sta.addr); 17707ac9a364SKalle Valo } 17717ac9a364SKalle Valo } 17727ac9a364SKalle Valo 17737ac9a364SKalle Valo static int 17747ac9a364SKalle Valo il_process_add_sta_resp(struct il_priv *il, struct il_addsta_cmd *addsta, 17757ac9a364SKalle Valo struct il_rx_pkt *pkt, bool sync) 17767ac9a364SKalle Valo { 17777ac9a364SKalle Valo u8 sta_id = addsta->sta.sta_id; 17787ac9a364SKalle Valo unsigned long flags; 17797ac9a364SKalle Valo int ret = -EIO; 17807ac9a364SKalle Valo 17817ac9a364SKalle Valo if (pkt->hdr.flags & IL_CMD_FAILED_MSK) { 17827ac9a364SKalle Valo IL_ERR("Bad return from C_ADD_STA (0x%08X)\n", pkt->hdr.flags); 17837ac9a364SKalle Valo return ret; 17847ac9a364SKalle Valo } 17857ac9a364SKalle Valo 17867ac9a364SKalle Valo D_INFO("Processing response for adding station %u\n", sta_id); 17877ac9a364SKalle Valo 17887ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags); 17897ac9a364SKalle Valo 17907ac9a364SKalle Valo switch (pkt->u.add_sta.status) { 17917ac9a364SKalle Valo case ADD_STA_SUCCESS_MSK: 17927ac9a364SKalle Valo D_INFO("C_ADD_STA PASSED\n"); 17937ac9a364SKalle Valo il_sta_ucode_activate(il, sta_id); 17947ac9a364SKalle Valo ret = 0; 17957ac9a364SKalle Valo break; 17967ac9a364SKalle Valo case ADD_STA_NO_ROOM_IN_TBL: 17977ac9a364SKalle Valo IL_ERR("Adding station %d failed, no room in table.\n", sta_id); 17987ac9a364SKalle Valo break; 17997ac9a364SKalle Valo case ADD_STA_NO_BLOCK_ACK_RESOURCE: 18007ac9a364SKalle Valo IL_ERR("Adding station %d failed, no block ack resource.\n", 18017ac9a364SKalle Valo sta_id); 18027ac9a364SKalle Valo break; 18037ac9a364SKalle Valo case ADD_STA_MODIFY_NON_EXIST_STA: 18047ac9a364SKalle Valo IL_ERR("Attempting to modify non-existing station %d\n", 18057ac9a364SKalle Valo sta_id); 18067ac9a364SKalle Valo break; 18077ac9a364SKalle Valo default: 18087ac9a364SKalle Valo D_ASSOC("Received C_ADD_STA:(0x%08X)\n", pkt->u.add_sta.status); 18097ac9a364SKalle Valo break; 18107ac9a364SKalle Valo } 18117ac9a364SKalle Valo 18127ac9a364SKalle Valo D_INFO("%s station id %u addr %pM\n", 18137ac9a364SKalle Valo il->stations[sta_id].sta.mode == 18147ac9a364SKalle Valo STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", sta_id, 18157ac9a364SKalle Valo il->stations[sta_id].sta.sta.addr); 18167ac9a364SKalle Valo 18177ac9a364SKalle Valo /* 18187ac9a364SKalle Valo * XXX: The MAC address in the command buffer is often changed from 18197ac9a364SKalle Valo * the original sent to the device. That is, the MAC address 18207ac9a364SKalle Valo * written to the command buffer often is not the same MAC address 18217ac9a364SKalle Valo * read from the command buffer when the command returns. This 18227ac9a364SKalle Valo * issue has not yet been resolved and this debugging is left to 18237ac9a364SKalle Valo * observe the problem. 18247ac9a364SKalle Valo */ 18257ac9a364SKalle Valo D_INFO("%s station according to cmd buffer %pM\n", 18267ac9a364SKalle Valo il->stations[sta_id].sta.mode == 18277ac9a364SKalle Valo STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", addsta->sta.addr); 18287ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags); 18297ac9a364SKalle Valo 18307ac9a364SKalle Valo return ret; 18317ac9a364SKalle Valo } 18327ac9a364SKalle Valo 18337ac9a364SKalle Valo static void 18347ac9a364SKalle Valo il_add_sta_callback(struct il_priv *il, struct il_device_cmd *cmd, 18357ac9a364SKalle Valo struct il_rx_pkt *pkt) 18367ac9a364SKalle Valo { 18377ac9a364SKalle Valo struct il_addsta_cmd *addsta = (struct il_addsta_cmd *)cmd->cmd.payload; 18387ac9a364SKalle Valo 18397ac9a364SKalle Valo il_process_add_sta_resp(il, addsta, pkt, false); 18407ac9a364SKalle Valo 18417ac9a364SKalle Valo } 18427ac9a364SKalle Valo 18437ac9a364SKalle Valo int 18447ac9a364SKalle Valo il_send_add_sta(struct il_priv *il, struct il_addsta_cmd *sta, u8 flags) 18457ac9a364SKalle Valo { 18467ac9a364SKalle Valo struct il_rx_pkt *pkt = NULL; 18477ac9a364SKalle Valo int ret = 0; 18487ac9a364SKalle Valo u8 data[sizeof(*sta)]; 18497ac9a364SKalle Valo struct il_host_cmd cmd = { 18507ac9a364SKalle Valo .id = C_ADD_STA, 18517ac9a364SKalle Valo .flags = flags, 18527ac9a364SKalle Valo .data = data, 18537ac9a364SKalle Valo }; 18547ac9a364SKalle Valo u8 sta_id __maybe_unused = sta->sta.sta_id; 18557ac9a364SKalle Valo 18567ac9a364SKalle Valo D_INFO("Adding sta %u (%pM) %ssynchronously\n", sta_id, sta->sta.addr, 18577ac9a364SKalle Valo flags & CMD_ASYNC ? "a" : ""); 18587ac9a364SKalle Valo 18597ac9a364SKalle Valo if (flags & CMD_ASYNC) 18607ac9a364SKalle Valo cmd.callback = il_add_sta_callback; 18617ac9a364SKalle Valo else { 18627ac9a364SKalle Valo cmd.flags |= CMD_WANT_SKB; 18637ac9a364SKalle Valo might_sleep(); 18647ac9a364SKalle Valo } 18657ac9a364SKalle Valo 18667ac9a364SKalle Valo cmd.len = il->ops->build_addsta_hcmd(sta, data); 18677ac9a364SKalle Valo ret = il_send_cmd(il, &cmd); 1868*3f0267f6SDan Carpenter if (ret) 18697ac9a364SKalle Valo return ret; 1870*3f0267f6SDan Carpenter if (flags & CMD_ASYNC) 1871*3f0267f6SDan Carpenter return 0; 18727ac9a364SKalle Valo 18737ac9a364SKalle Valo pkt = (struct il_rx_pkt *)cmd.reply_page; 18747ac9a364SKalle Valo ret = il_process_add_sta_resp(il, sta, pkt, true); 1875*3f0267f6SDan Carpenter 18767ac9a364SKalle Valo il_free_pages(il, cmd.reply_page); 18777ac9a364SKalle Valo 18787ac9a364SKalle Valo return ret; 18797ac9a364SKalle Valo } 18807ac9a364SKalle Valo EXPORT_SYMBOL(il_send_add_sta); 18817ac9a364SKalle Valo 18827ac9a364SKalle Valo static void 18837ac9a364SKalle Valo il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta) 18847ac9a364SKalle Valo { 18857ac9a364SKalle Valo struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; 18867ac9a364SKalle Valo __le32 sta_flags; 18877ac9a364SKalle Valo 18887ac9a364SKalle Valo if (!sta || !sta_ht_inf->ht_supported) 18897ac9a364SKalle Valo goto done; 18907ac9a364SKalle Valo 18917ac9a364SKalle Valo D_ASSOC("spatial multiplexing power save mode: %s\n", 18927ac9a364SKalle Valo (sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" : 18937ac9a364SKalle Valo (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" : 18947ac9a364SKalle Valo "disabled"); 18957ac9a364SKalle Valo 18967ac9a364SKalle Valo sta_flags = il->stations[idx].sta.station_flags; 18977ac9a364SKalle Valo 18987ac9a364SKalle Valo sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); 18997ac9a364SKalle Valo 19007ac9a364SKalle Valo switch (sta->smps_mode) { 19017ac9a364SKalle Valo case IEEE80211_SMPS_STATIC: 19027ac9a364SKalle Valo sta_flags |= STA_FLG_MIMO_DIS_MSK; 19037ac9a364SKalle Valo break; 19047ac9a364SKalle Valo case IEEE80211_SMPS_DYNAMIC: 19057ac9a364SKalle Valo sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; 19067ac9a364SKalle Valo break; 19077ac9a364SKalle Valo case IEEE80211_SMPS_OFF: 19087ac9a364SKalle Valo break; 19097ac9a364SKalle Valo default: 19107ac9a364SKalle Valo IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode); 19117ac9a364SKalle Valo break; 19127ac9a364SKalle Valo } 19137ac9a364SKalle Valo 19147ac9a364SKalle Valo sta_flags |= 19157ac9a364SKalle Valo cpu_to_le32((u32) sta_ht_inf-> 19167ac9a364SKalle Valo ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); 19177ac9a364SKalle Valo 19187ac9a364SKalle Valo sta_flags |= 19197ac9a364SKalle Valo cpu_to_le32((u32) sta_ht_inf-> 19207ac9a364SKalle Valo ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); 19217ac9a364SKalle Valo 19227ac9a364SKalle Valo if (il_is_ht40_tx_allowed(il, &sta->ht_cap)) 19237ac9a364SKalle Valo sta_flags |= STA_FLG_HT40_EN_MSK; 19247ac9a364SKalle Valo else 19257ac9a364SKalle Valo sta_flags &= ~STA_FLG_HT40_EN_MSK; 19267ac9a364SKalle Valo 19277ac9a364SKalle Valo il->stations[idx].sta.station_flags = sta_flags; 19287ac9a364SKalle Valo done: 19297ac9a364SKalle Valo return; 19307ac9a364SKalle Valo } 19317ac9a364SKalle Valo 19327ac9a364SKalle Valo /** 19337ac9a364SKalle Valo * il_prep_station - Prepare station information for addition 19347ac9a364SKalle Valo * 19357ac9a364SKalle Valo * should be called with sta_lock held 19367ac9a364SKalle Valo */ 19377ac9a364SKalle Valo u8 19387ac9a364SKalle Valo il_prep_station(struct il_priv *il, const u8 *addr, bool is_ap, 19397ac9a364SKalle Valo struct ieee80211_sta *sta) 19407ac9a364SKalle Valo { 19417ac9a364SKalle Valo struct il_station_entry *station; 19427ac9a364SKalle Valo int i; 19437ac9a364SKalle Valo u8 sta_id = IL_INVALID_STATION; 19447ac9a364SKalle Valo u16 rate; 19457ac9a364SKalle Valo 19467ac9a364SKalle Valo if (is_ap) 19477ac9a364SKalle Valo sta_id = IL_AP_ID; 19487ac9a364SKalle Valo else if (is_broadcast_ether_addr(addr)) 19497ac9a364SKalle Valo sta_id = il->hw_params.bcast_id; 19507ac9a364SKalle Valo else 19517ac9a364SKalle Valo for (i = IL_STA_ID; i < il->hw_params.max_stations; i++) { 19527ac9a364SKalle Valo if (ether_addr_equal(il->stations[i].sta.sta.addr, 19537ac9a364SKalle Valo addr)) { 19547ac9a364SKalle Valo sta_id = i; 19557ac9a364SKalle Valo break; 19567ac9a364SKalle Valo } 19577ac9a364SKalle Valo 19587ac9a364SKalle Valo if (!il->stations[i].used && 19597ac9a364SKalle Valo sta_id == IL_INVALID_STATION) 19607ac9a364SKalle Valo sta_id = i; 19617ac9a364SKalle Valo } 19627ac9a364SKalle Valo 19637ac9a364SKalle Valo /* 19647ac9a364SKalle Valo * These two conditions have the same outcome, but keep them 19657ac9a364SKalle Valo * separate 19667ac9a364SKalle Valo */ 19677ac9a364SKalle Valo if (unlikely(sta_id == IL_INVALID_STATION)) 19687ac9a364SKalle Valo return sta_id; 19697ac9a364SKalle Valo 19707ac9a364SKalle Valo /* 19717ac9a364SKalle Valo * uCode is not able to deal with multiple requests to add a 19727ac9a364SKalle Valo * station. Keep track if one is in progress so that we do not send 19737ac9a364SKalle Valo * another. 19747ac9a364SKalle Valo */ 19757ac9a364SKalle Valo if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) { 19767ac9a364SKalle Valo D_INFO("STA %d already in process of being added.\n", sta_id); 19777ac9a364SKalle Valo return sta_id; 19787ac9a364SKalle Valo } 19797ac9a364SKalle Valo 19807ac9a364SKalle Valo if ((il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE) && 19817ac9a364SKalle Valo (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) && 19827ac9a364SKalle Valo ether_addr_equal(il->stations[sta_id].sta.sta.addr, addr)) { 19837ac9a364SKalle Valo D_ASSOC("STA %d (%pM) already added, not adding again.\n", 19847ac9a364SKalle Valo sta_id, addr); 19857ac9a364SKalle Valo return sta_id; 19867ac9a364SKalle Valo } 19877ac9a364SKalle Valo 19887ac9a364SKalle Valo station = &il->stations[sta_id]; 19897ac9a364SKalle Valo station->used = IL_STA_DRIVER_ACTIVE; 19907ac9a364SKalle Valo D_ASSOC("Add STA to driver ID %d: %pM\n", sta_id, addr); 19917ac9a364SKalle Valo il->num_stations++; 19927ac9a364SKalle Valo 19937ac9a364SKalle Valo /* Set up the C_ADD_STA command to send to device */ 19947ac9a364SKalle Valo memset(&station->sta, 0, sizeof(struct il_addsta_cmd)); 19957ac9a364SKalle Valo memcpy(station->sta.sta.addr, addr, ETH_ALEN); 19967ac9a364SKalle Valo station->sta.mode = 0; 19977ac9a364SKalle Valo station->sta.sta.sta_id = sta_id; 19987ac9a364SKalle Valo station->sta.station_flags = 0; 19997ac9a364SKalle Valo 20007ac9a364SKalle Valo /* 20017ac9a364SKalle Valo * OK to call unconditionally, since local stations (IBSS BSSID 20027ac9a364SKalle Valo * STA and broadcast STA) pass in a NULL sta, and mac80211 20037ac9a364SKalle Valo * doesn't allow HT IBSS. 20047ac9a364SKalle Valo */ 20057ac9a364SKalle Valo il_set_ht_add_station(il, sta_id, sta); 20067ac9a364SKalle Valo 20077ac9a364SKalle Valo /* 3945 only */ 20087ac9a364SKalle Valo rate = (il->band == IEEE80211_BAND_5GHZ) ? RATE_6M_PLCP : RATE_1M_PLCP; 20097ac9a364SKalle Valo /* Turn on both antennas for the station... */ 20107ac9a364SKalle Valo station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); 20117ac9a364SKalle Valo 20127ac9a364SKalle Valo return sta_id; 20137ac9a364SKalle Valo 20147ac9a364SKalle Valo } 20157ac9a364SKalle Valo EXPORT_SYMBOL_GPL(il_prep_station); 20167ac9a364SKalle Valo 20177ac9a364SKalle Valo #define STA_WAIT_TIMEOUT (HZ/2) 20187ac9a364SKalle Valo 20197ac9a364SKalle Valo /** 20207ac9a364SKalle Valo * il_add_station_common - 20217ac9a364SKalle Valo */ 20227ac9a364SKalle Valo int 20237ac9a364SKalle Valo il_add_station_common(struct il_priv *il, const u8 *addr, bool is_ap, 20247ac9a364SKalle Valo struct ieee80211_sta *sta, u8 *sta_id_r) 20257ac9a364SKalle Valo { 20267ac9a364SKalle Valo unsigned long flags_spin; 20277ac9a364SKalle Valo int ret = 0; 20287ac9a364SKalle Valo u8 sta_id; 20297ac9a364SKalle Valo struct il_addsta_cmd sta_cmd; 20307ac9a364SKalle Valo 20317ac9a364SKalle Valo *sta_id_r = 0; 20327ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 20337ac9a364SKalle Valo sta_id = il_prep_station(il, addr, is_ap, sta); 20347ac9a364SKalle Valo if (sta_id == IL_INVALID_STATION) { 20357ac9a364SKalle Valo IL_ERR("Unable to prepare station %pM for addition\n", addr); 20367ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 20377ac9a364SKalle Valo return -EINVAL; 20387ac9a364SKalle Valo } 20397ac9a364SKalle Valo 20407ac9a364SKalle Valo /* 20417ac9a364SKalle Valo * uCode is not able to deal with multiple requests to add a 20427ac9a364SKalle Valo * station. Keep track if one is in progress so that we do not send 20437ac9a364SKalle Valo * another. 20447ac9a364SKalle Valo */ 20457ac9a364SKalle Valo if (il->stations[sta_id].used & IL_STA_UCODE_INPROGRESS) { 20467ac9a364SKalle Valo D_INFO("STA %d already in process of being added.\n", sta_id); 20477ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 20487ac9a364SKalle Valo return -EEXIST; 20497ac9a364SKalle Valo } 20507ac9a364SKalle Valo 20517ac9a364SKalle Valo if ((il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE) && 20527ac9a364SKalle Valo (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE)) { 20537ac9a364SKalle Valo D_ASSOC("STA %d (%pM) already added, not adding again.\n", 20547ac9a364SKalle Valo sta_id, addr); 20557ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 20567ac9a364SKalle Valo return -EEXIST; 20577ac9a364SKalle Valo } 20587ac9a364SKalle Valo 20597ac9a364SKalle Valo il->stations[sta_id].used |= IL_STA_UCODE_INPROGRESS; 20607ac9a364SKalle Valo memcpy(&sta_cmd, &il->stations[sta_id].sta, 20617ac9a364SKalle Valo sizeof(struct il_addsta_cmd)); 20627ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 20637ac9a364SKalle Valo 20647ac9a364SKalle Valo /* Add station to device's station table */ 20657ac9a364SKalle Valo ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC); 20667ac9a364SKalle Valo if (ret) { 20677ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 20687ac9a364SKalle Valo IL_ERR("Adding station %pM failed.\n", 20697ac9a364SKalle Valo il->stations[sta_id].sta.sta.addr); 20707ac9a364SKalle Valo il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE; 20717ac9a364SKalle Valo il->stations[sta_id].used &= ~IL_STA_UCODE_INPROGRESS; 20727ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 20737ac9a364SKalle Valo } 20747ac9a364SKalle Valo *sta_id_r = sta_id; 20757ac9a364SKalle Valo return ret; 20767ac9a364SKalle Valo } 20777ac9a364SKalle Valo EXPORT_SYMBOL(il_add_station_common); 20787ac9a364SKalle Valo 20797ac9a364SKalle Valo /** 20807ac9a364SKalle Valo * il_sta_ucode_deactivate - deactivate ucode status for a station 20817ac9a364SKalle Valo * 20827ac9a364SKalle Valo * il->sta_lock must be held 20837ac9a364SKalle Valo */ 20847ac9a364SKalle Valo static void 20857ac9a364SKalle Valo il_sta_ucode_deactivate(struct il_priv *il, u8 sta_id) 20867ac9a364SKalle Valo { 20877ac9a364SKalle Valo /* Ucode must be active and driver must be non active */ 20887ac9a364SKalle Valo if ((il->stations[sta_id]. 20897ac9a364SKalle Valo used & (IL_STA_UCODE_ACTIVE | IL_STA_DRIVER_ACTIVE)) != 20907ac9a364SKalle Valo IL_STA_UCODE_ACTIVE) 20917ac9a364SKalle Valo IL_ERR("removed non active STA %u\n", sta_id); 20927ac9a364SKalle Valo 20937ac9a364SKalle Valo il->stations[sta_id].used &= ~IL_STA_UCODE_ACTIVE; 20947ac9a364SKalle Valo 20957ac9a364SKalle Valo memset(&il->stations[sta_id], 0, sizeof(struct il_station_entry)); 20967ac9a364SKalle Valo D_ASSOC("Removed STA %u\n", sta_id); 20977ac9a364SKalle Valo } 20987ac9a364SKalle Valo 20997ac9a364SKalle Valo static int 21007ac9a364SKalle Valo il_send_remove_station(struct il_priv *il, const u8 * addr, int sta_id, 21017ac9a364SKalle Valo bool temporary) 21027ac9a364SKalle Valo { 21037ac9a364SKalle Valo struct il_rx_pkt *pkt; 21047ac9a364SKalle Valo int ret; 21057ac9a364SKalle Valo 21067ac9a364SKalle Valo unsigned long flags_spin; 21077ac9a364SKalle Valo struct il_rem_sta_cmd rm_sta_cmd; 21087ac9a364SKalle Valo 21097ac9a364SKalle Valo struct il_host_cmd cmd = { 21107ac9a364SKalle Valo .id = C_REM_STA, 21117ac9a364SKalle Valo .len = sizeof(struct il_rem_sta_cmd), 21127ac9a364SKalle Valo .flags = CMD_SYNC, 21137ac9a364SKalle Valo .data = &rm_sta_cmd, 21147ac9a364SKalle Valo }; 21157ac9a364SKalle Valo 21167ac9a364SKalle Valo memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); 21177ac9a364SKalle Valo rm_sta_cmd.num_sta = 1; 21187ac9a364SKalle Valo memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN); 21197ac9a364SKalle Valo 21207ac9a364SKalle Valo cmd.flags |= CMD_WANT_SKB; 21217ac9a364SKalle Valo 21227ac9a364SKalle Valo ret = il_send_cmd(il, &cmd); 21237ac9a364SKalle Valo 21247ac9a364SKalle Valo if (ret) 21257ac9a364SKalle Valo return ret; 21267ac9a364SKalle Valo 21277ac9a364SKalle Valo pkt = (struct il_rx_pkt *)cmd.reply_page; 21287ac9a364SKalle Valo if (pkt->hdr.flags & IL_CMD_FAILED_MSK) { 21297ac9a364SKalle Valo IL_ERR("Bad return from C_REM_STA (0x%08X)\n", pkt->hdr.flags); 21307ac9a364SKalle Valo ret = -EIO; 21317ac9a364SKalle Valo } 21327ac9a364SKalle Valo 21337ac9a364SKalle Valo if (!ret) { 21347ac9a364SKalle Valo switch (pkt->u.rem_sta.status) { 21357ac9a364SKalle Valo case REM_STA_SUCCESS_MSK: 21367ac9a364SKalle Valo if (!temporary) { 21377ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 21387ac9a364SKalle Valo il_sta_ucode_deactivate(il, sta_id); 21397ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, 21407ac9a364SKalle Valo flags_spin); 21417ac9a364SKalle Valo } 21427ac9a364SKalle Valo D_ASSOC("C_REM_STA PASSED\n"); 21437ac9a364SKalle Valo break; 21447ac9a364SKalle Valo default: 21457ac9a364SKalle Valo ret = -EIO; 21467ac9a364SKalle Valo IL_ERR("C_REM_STA failed\n"); 21477ac9a364SKalle Valo break; 21487ac9a364SKalle Valo } 21497ac9a364SKalle Valo } 21507ac9a364SKalle Valo il_free_pages(il, cmd.reply_page); 21517ac9a364SKalle Valo 21527ac9a364SKalle Valo return ret; 21537ac9a364SKalle Valo } 21547ac9a364SKalle Valo 21557ac9a364SKalle Valo /** 21567ac9a364SKalle Valo * il_remove_station - Remove driver's knowledge of station. 21577ac9a364SKalle Valo */ 21587ac9a364SKalle Valo int 21597ac9a364SKalle Valo il_remove_station(struct il_priv *il, const u8 sta_id, const u8 * addr) 21607ac9a364SKalle Valo { 21617ac9a364SKalle Valo unsigned long flags; 21627ac9a364SKalle Valo 21637ac9a364SKalle Valo if (!il_is_ready(il)) { 21647ac9a364SKalle Valo D_INFO("Unable to remove station %pM, device not ready.\n", 21657ac9a364SKalle Valo addr); 21667ac9a364SKalle Valo /* 21677ac9a364SKalle Valo * It is typical for stations to be removed when we are 21687ac9a364SKalle Valo * going down. Return success since device will be down 21697ac9a364SKalle Valo * soon anyway 21707ac9a364SKalle Valo */ 21717ac9a364SKalle Valo return 0; 21727ac9a364SKalle Valo } 21737ac9a364SKalle Valo 21747ac9a364SKalle Valo D_ASSOC("Removing STA from driver:%d %pM\n", sta_id, addr); 21757ac9a364SKalle Valo 21767ac9a364SKalle Valo if (WARN_ON(sta_id == IL_INVALID_STATION)) 21777ac9a364SKalle Valo return -EINVAL; 21787ac9a364SKalle Valo 21797ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags); 21807ac9a364SKalle Valo 21817ac9a364SKalle Valo if (!(il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE)) { 21827ac9a364SKalle Valo D_INFO("Removing %pM but non DRIVER active\n", addr); 21837ac9a364SKalle Valo goto out_err; 21847ac9a364SKalle Valo } 21857ac9a364SKalle Valo 21867ac9a364SKalle Valo if (!(il->stations[sta_id].used & IL_STA_UCODE_ACTIVE)) { 21877ac9a364SKalle Valo D_INFO("Removing %pM but non UCODE active\n", addr); 21887ac9a364SKalle Valo goto out_err; 21897ac9a364SKalle Valo } 21907ac9a364SKalle Valo 21917ac9a364SKalle Valo if (il->stations[sta_id].used & IL_STA_LOCAL) { 21927ac9a364SKalle Valo kfree(il->stations[sta_id].lq); 21937ac9a364SKalle Valo il->stations[sta_id].lq = NULL; 21947ac9a364SKalle Valo } 21957ac9a364SKalle Valo 21967ac9a364SKalle Valo il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE; 21977ac9a364SKalle Valo 21987ac9a364SKalle Valo il->num_stations--; 21997ac9a364SKalle Valo 22007ac9a364SKalle Valo BUG_ON(il->num_stations < 0); 22017ac9a364SKalle Valo 22027ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags); 22037ac9a364SKalle Valo 22047ac9a364SKalle Valo return il_send_remove_station(il, addr, sta_id, false); 22057ac9a364SKalle Valo out_err: 22067ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags); 22077ac9a364SKalle Valo return -EINVAL; 22087ac9a364SKalle Valo } 22097ac9a364SKalle Valo EXPORT_SYMBOL_GPL(il_remove_station); 22107ac9a364SKalle Valo 22117ac9a364SKalle Valo /** 22127ac9a364SKalle Valo * il_clear_ucode_stations - clear ucode station table bits 22137ac9a364SKalle Valo * 22147ac9a364SKalle Valo * This function clears all the bits in the driver indicating 22157ac9a364SKalle Valo * which stations are active in the ucode. Call when something 22167ac9a364SKalle Valo * other than explicit station management would cause this in 22177ac9a364SKalle Valo * the ucode, e.g. unassociated RXON. 22187ac9a364SKalle Valo */ 22197ac9a364SKalle Valo void 22207ac9a364SKalle Valo il_clear_ucode_stations(struct il_priv *il) 22217ac9a364SKalle Valo { 22227ac9a364SKalle Valo int i; 22237ac9a364SKalle Valo unsigned long flags_spin; 22247ac9a364SKalle Valo bool cleared = false; 22257ac9a364SKalle Valo 22267ac9a364SKalle Valo D_INFO("Clearing ucode stations in driver\n"); 22277ac9a364SKalle Valo 22287ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 22297ac9a364SKalle Valo for (i = 0; i < il->hw_params.max_stations; i++) { 22307ac9a364SKalle Valo if (il->stations[i].used & IL_STA_UCODE_ACTIVE) { 22317ac9a364SKalle Valo D_INFO("Clearing ucode active for station %d\n", i); 22327ac9a364SKalle Valo il->stations[i].used &= ~IL_STA_UCODE_ACTIVE; 22337ac9a364SKalle Valo cleared = true; 22347ac9a364SKalle Valo } 22357ac9a364SKalle Valo } 22367ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 22377ac9a364SKalle Valo 22387ac9a364SKalle Valo if (!cleared) 22397ac9a364SKalle Valo D_INFO("No active stations found to be cleared\n"); 22407ac9a364SKalle Valo } 22417ac9a364SKalle Valo EXPORT_SYMBOL(il_clear_ucode_stations); 22427ac9a364SKalle Valo 22437ac9a364SKalle Valo /** 22447ac9a364SKalle Valo * il_restore_stations() - Restore driver known stations to device 22457ac9a364SKalle Valo * 22467ac9a364SKalle Valo * All stations considered active by driver, but not present in ucode, is 22477ac9a364SKalle Valo * restored. 22487ac9a364SKalle Valo * 22497ac9a364SKalle Valo * Function sleeps. 22507ac9a364SKalle Valo */ 22517ac9a364SKalle Valo void 22527ac9a364SKalle Valo il_restore_stations(struct il_priv *il) 22537ac9a364SKalle Valo { 22547ac9a364SKalle Valo struct il_addsta_cmd sta_cmd; 22557ac9a364SKalle Valo struct il_link_quality_cmd lq; 22567ac9a364SKalle Valo unsigned long flags_spin; 22577ac9a364SKalle Valo int i; 22587ac9a364SKalle Valo bool found = false; 22597ac9a364SKalle Valo int ret; 22607ac9a364SKalle Valo bool send_lq; 22617ac9a364SKalle Valo 22627ac9a364SKalle Valo if (!il_is_ready(il)) { 22637ac9a364SKalle Valo D_INFO("Not ready yet, not restoring any stations.\n"); 22647ac9a364SKalle Valo return; 22657ac9a364SKalle Valo } 22667ac9a364SKalle Valo 22677ac9a364SKalle Valo D_ASSOC("Restoring all known stations ... start.\n"); 22687ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 22697ac9a364SKalle Valo for (i = 0; i < il->hw_params.max_stations; i++) { 22707ac9a364SKalle Valo if ((il->stations[i].used & IL_STA_DRIVER_ACTIVE) && 22717ac9a364SKalle Valo !(il->stations[i].used & IL_STA_UCODE_ACTIVE)) { 22727ac9a364SKalle Valo D_ASSOC("Restoring sta %pM\n", 22737ac9a364SKalle Valo il->stations[i].sta.sta.addr); 22747ac9a364SKalle Valo il->stations[i].sta.mode = 0; 22757ac9a364SKalle Valo il->stations[i].used |= IL_STA_UCODE_INPROGRESS; 22767ac9a364SKalle Valo found = true; 22777ac9a364SKalle Valo } 22787ac9a364SKalle Valo } 22797ac9a364SKalle Valo 22807ac9a364SKalle Valo for (i = 0; i < il->hw_params.max_stations; i++) { 22817ac9a364SKalle Valo if ((il->stations[i].used & IL_STA_UCODE_INPROGRESS)) { 22827ac9a364SKalle Valo memcpy(&sta_cmd, &il->stations[i].sta, 22837ac9a364SKalle Valo sizeof(struct il_addsta_cmd)); 22847ac9a364SKalle Valo send_lq = false; 22857ac9a364SKalle Valo if (il->stations[i].lq) { 22867ac9a364SKalle Valo memcpy(&lq, il->stations[i].lq, 22877ac9a364SKalle Valo sizeof(struct il_link_quality_cmd)); 22887ac9a364SKalle Valo send_lq = true; 22897ac9a364SKalle Valo } 22907ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 22917ac9a364SKalle Valo ret = il_send_add_sta(il, &sta_cmd, CMD_SYNC); 22927ac9a364SKalle Valo if (ret) { 22937ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 22947ac9a364SKalle Valo IL_ERR("Adding station %pM failed.\n", 22957ac9a364SKalle Valo il->stations[i].sta.sta.addr); 22967ac9a364SKalle Valo il->stations[i].used &= ~IL_STA_DRIVER_ACTIVE; 22977ac9a364SKalle Valo il->stations[i].used &= 22987ac9a364SKalle Valo ~IL_STA_UCODE_INPROGRESS; 22997ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, 23007ac9a364SKalle Valo flags_spin); 23017ac9a364SKalle Valo } 23027ac9a364SKalle Valo /* 23037ac9a364SKalle Valo * Rate scaling has already been initialized, send 23047ac9a364SKalle Valo * current LQ command 23057ac9a364SKalle Valo */ 23067ac9a364SKalle Valo if (send_lq) 23077ac9a364SKalle Valo il_send_lq_cmd(il, &lq, CMD_SYNC, true); 23087ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 23097ac9a364SKalle Valo il->stations[i].used &= ~IL_STA_UCODE_INPROGRESS; 23107ac9a364SKalle Valo } 23117ac9a364SKalle Valo } 23127ac9a364SKalle Valo 23137ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 23147ac9a364SKalle Valo if (!found) 23157ac9a364SKalle Valo D_INFO("Restoring all known stations" 23167ac9a364SKalle Valo " .... no stations to be restored.\n"); 23177ac9a364SKalle Valo else 23187ac9a364SKalle Valo D_INFO("Restoring all known stations" " .... complete.\n"); 23197ac9a364SKalle Valo } 23207ac9a364SKalle Valo EXPORT_SYMBOL(il_restore_stations); 23217ac9a364SKalle Valo 23227ac9a364SKalle Valo int 23237ac9a364SKalle Valo il_get_free_ucode_key_idx(struct il_priv *il) 23247ac9a364SKalle Valo { 23257ac9a364SKalle Valo int i; 23267ac9a364SKalle Valo 23277ac9a364SKalle Valo for (i = 0; i < il->sta_key_max_num; i++) 23287ac9a364SKalle Valo if (!test_and_set_bit(i, &il->ucode_key_table)) 23297ac9a364SKalle Valo return i; 23307ac9a364SKalle Valo 23317ac9a364SKalle Valo return WEP_INVALID_OFFSET; 23327ac9a364SKalle Valo } 23337ac9a364SKalle Valo EXPORT_SYMBOL(il_get_free_ucode_key_idx); 23347ac9a364SKalle Valo 23357ac9a364SKalle Valo void 23367ac9a364SKalle Valo il_dealloc_bcast_stations(struct il_priv *il) 23377ac9a364SKalle Valo { 23387ac9a364SKalle Valo unsigned long flags; 23397ac9a364SKalle Valo int i; 23407ac9a364SKalle Valo 23417ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags); 23427ac9a364SKalle Valo for (i = 0; i < il->hw_params.max_stations; i++) { 23437ac9a364SKalle Valo if (!(il->stations[i].used & IL_STA_BCAST)) 23447ac9a364SKalle Valo continue; 23457ac9a364SKalle Valo 23467ac9a364SKalle Valo il->stations[i].used &= ~IL_STA_UCODE_ACTIVE; 23477ac9a364SKalle Valo il->num_stations--; 23487ac9a364SKalle Valo BUG_ON(il->num_stations < 0); 23497ac9a364SKalle Valo kfree(il->stations[i].lq); 23507ac9a364SKalle Valo il->stations[i].lq = NULL; 23517ac9a364SKalle Valo } 23527ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags); 23537ac9a364SKalle Valo } 23547ac9a364SKalle Valo EXPORT_SYMBOL_GPL(il_dealloc_bcast_stations); 23557ac9a364SKalle Valo 23567ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 23577ac9a364SKalle Valo static void 23587ac9a364SKalle Valo il_dump_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq) 23597ac9a364SKalle Valo { 23607ac9a364SKalle Valo int i; 23617ac9a364SKalle Valo D_RATE("lq station id 0x%x\n", lq->sta_id); 23627ac9a364SKalle Valo D_RATE("lq ant 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, 23637ac9a364SKalle Valo lq->general_params.dual_stream_ant_msk); 23647ac9a364SKalle Valo 23657ac9a364SKalle Valo for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) 23667ac9a364SKalle Valo D_RATE("lq idx %d 0x%X\n", i, lq->rs_table[i].rate_n_flags); 23677ac9a364SKalle Valo } 23687ac9a364SKalle Valo #else 23697ac9a364SKalle Valo static inline void 23707ac9a364SKalle Valo il_dump_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq) 23717ac9a364SKalle Valo { 23727ac9a364SKalle Valo } 23737ac9a364SKalle Valo #endif 23747ac9a364SKalle Valo 23757ac9a364SKalle Valo /** 23767ac9a364SKalle Valo * il_is_lq_table_valid() - Test one aspect of LQ cmd for validity 23777ac9a364SKalle Valo * 23787ac9a364SKalle Valo * It sometimes happens when a HT rate has been in use and we 23797ac9a364SKalle Valo * loose connectivity with AP then mac80211 will first tell us that the 23807ac9a364SKalle Valo * current channel is not HT anymore before removing the station. In such a 23817ac9a364SKalle Valo * scenario the RXON flags will be updated to indicate we are not 23827ac9a364SKalle Valo * communicating HT anymore, but the LQ command may still contain HT rates. 23837ac9a364SKalle Valo * Test for this to prevent driver from sending LQ command between the time 23847ac9a364SKalle Valo * RXON flags are updated and when LQ command is updated. 23857ac9a364SKalle Valo */ 23867ac9a364SKalle Valo static bool 23877ac9a364SKalle Valo il_is_lq_table_valid(struct il_priv *il, struct il_link_quality_cmd *lq) 23887ac9a364SKalle Valo { 23897ac9a364SKalle Valo int i; 23907ac9a364SKalle Valo 23917ac9a364SKalle Valo if (il->ht.enabled) 23927ac9a364SKalle Valo return true; 23937ac9a364SKalle Valo 23947ac9a364SKalle Valo D_INFO("Channel %u is not an HT channel\n", il->active.channel); 23957ac9a364SKalle Valo for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { 23967ac9a364SKalle Valo if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) { 23977ac9a364SKalle Valo D_INFO("idx %d of LQ expects HT channel\n", i); 23987ac9a364SKalle Valo return false; 23997ac9a364SKalle Valo } 24007ac9a364SKalle Valo } 24017ac9a364SKalle Valo return true; 24027ac9a364SKalle Valo } 24037ac9a364SKalle Valo 24047ac9a364SKalle Valo /** 24057ac9a364SKalle Valo * il_send_lq_cmd() - Send link quality command 24067ac9a364SKalle Valo * @init: This command is sent as part of station initialization right 24077ac9a364SKalle Valo * after station has been added. 24087ac9a364SKalle Valo * 24097ac9a364SKalle Valo * The link quality command is sent as the last step of station creation. 24107ac9a364SKalle Valo * This is the special case in which init is set and we call a callback in 24117ac9a364SKalle Valo * this case to clear the state indicating that station creation is in 24127ac9a364SKalle Valo * progress. 24137ac9a364SKalle Valo */ 24147ac9a364SKalle Valo int 24157ac9a364SKalle Valo il_send_lq_cmd(struct il_priv *il, struct il_link_quality_cmd *lq, 24167ac9a364SKalle Valo u8 flags, bool init) 24177ac9a364SKalle Valo { 24187ac9a364SKalle Valo int ret = 0; 24197ac9a364SKalle Valo unsigned long flags_spin; 24207ac9a364SKalle Valo 24217ac9a364SKalle Valo struct il_host_cmd cmd = { 24227ac9a364SKalle Valo .id = C_TX_LINK_QUALITY_CMD, 24237ac9a364SKalle Valo .len = sizeof(struct il_link_quality_cmd), 24247ac9a364SKalle Valo .flags = flags, 24257ac9a364SKalle Valo .data = lq, 24267ac9a364SKalle Valo }; 24277ac9a364SKalle Valo 24287ac9a364SKalle Valo if (WARN_ON(lq->sta_id == IL_INVALID_STATION)) 24297ac9a364SKalle Valo return -EINVAL; 24307ac9a364SKalle Valo 24317ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 24327ac9a364SKalle Valo if (!(il->stations[lq->sta_id].used & IL_STA_DRIVER_ACTIVE)) { 24337ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 24347ac9a364SKalle Valo return -EINVAL; 24357ac9a364SKalle Valo } 24367ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 24377ac9a364SKalle Valo 24387ac9a364SKalle Valo il_dump_lq_cmd(il, lq); 24397ac9a364SKalle Valo BUG_ON(init && (cmd.flags & CMD_ASYNC)); 24407ac9a364SKalle Valo 24417ac9a364SKalle Valo if (il_is_lq_table_valid(il, lq)) 24427ac9a364SKalle Valo ret = il_send_cmd(il, &cmd); 24437ac9a364SKalle Valo else 24447ac9a364SKalle Valo ret = -EINVAL; 24457ac9a364SKalle Valo 24467ac9a364SKalle Valo if (cmd.flags & CMD_ASYNC) 24477ac9a364SKalle Valo return ret; 24487ac9a364SKalle Valo 24497ac9a364SKalle Valo if (init) { 24507ac9a364SKalle Valo D_INFO("init LQ command complete," 24517ac9a364SKalle Valo " clearing sta addition status for sta %d\n", 24527ac9a364SKalle Valo lq->sta_id); 24537ac9a364SKalle Valo spin_lock_irqsave(&il->sta_lock, flags_spin); 24547ac9a364SKalle Valo il->stations[lq->sta_id].used &= ~IL_STA_UCODE_INPROGRESS; 24557ac9a364SKalle Valo spin_unlock_irqrestore(&il->sta_lock, flags_spin); 24567ac9a364SKalle Valo } 24577ac9a364SKalle Valo return ret; 24587ac9a364SKalle Valo } 24597ac9a364SKalle Valo EXPORT_SYMBOL(il_send_lq_cmd); 24607ac9a364SKalle Valo 24617ac9a364SKalle Valo int 24627ac9a364SKalle Valo il_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 24637ac9a364SKalle Valo struct ieee80211_sta *sta) 24647ac9a364SKalle Valo { 24657ac9a364SKalle Valo struct il_priv *il = hw->priv; 24667ac9a364SKalle Valo struct il_station_priv_common *sta_common = (void *)sta->drv_priv; 24677ac9a364SKalle Valo int ret; 24687ac9a364SKalle Valo 24697ac9a364SKalle Valo mutex_lock(&il->mutex); 24707ac9a364SKalle Valo D_MAC80211("enter station %pM\n", sta->addr); 24717ac9a364SKalle Valo 24727ac9a364SKalle Valo ret = il_remove_station(il, sta_common->sta_id, sta->addr); 24737ac9a364SKalle Valo if (ret) 24747ac9a364SKalle Valo IL_ERR("Error removing station %pM\n", sta->addr); 24757ac9a364SKalle Valo 24767ac9a364SKalle Valo D_MAC80211("leave ret %d\n", ret); 24777ac9a364SKalle Valo mutex_unlock(&il->mutex); 24787ac9a364SKalle Valo 24797ac9a364SKalle Valo return ret; 24807ac9a364SKalle Valo } 24817ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_sta_remove); 24827ac9a364SKalle Valo 24837ac9a364SKalle Valo /************************** RX-FUNCTIONS ****************************/ 24847ac9a364SKalle Valo /* 24857ac9a364SKalle Valo * Rx theory of operation 24867ac9a364SKalle Valo * 24877ac9a364SKalle Valo * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), 24887ac9a364SKalle Valo * each of which point to Receive Buffers to be filled by the NIC. These get 24897ac9a364SKalle Valo * used not only for Rx frames, but for any command response or notification 24907ac9a364SKalle Valo * from the NIC. The driver and NIC manage the Rx buffers by means 24917ac9a364SKalle Valo * of idxes into the circular buffer. 24927ac9a364SKalle Valo * 24937ac9a364SKalle Valo * Rx Queue Indexes 24947ac9a364SKalle Valo * The host/firmware share two idx registers for managing the Rx buffers. 24957ac9a364SKalle Valo * 24967ac9a364SKalle Valo * The READ idx maps to the first position that the firmware may be writing 24977ac9a364SKalle Valo * to -- the driver can read up to (but not including) this position and get 24987ac9a364SKalle Valo * good data. 24997ac9a364SKalle Valo * The READ idx is managed by the firmware once the card is enabled. 25007ac9a364SKalle Valo * 25017ac9a364SKalle Valo * The WRITE idx maps to the last position the driver has read from -- the 25027ac9a364SKalle Valo * position preceding WRITE is the last slot the firmware can place a packet. 25037ac9a364SKalle Valo * 25047ac9a364SKalle Valo * The queue is empty (no good data) if WRITE = READ - 1, and is full if 25057ac9a364SKalle Valo * WRITE = READ. 25067ac9a364SKalle Valo * 25077ac9a364SKalle Valo * During initialization, the host sets up the READ queue position to the first 25087ac9a364SKalle Valo * IDX position, and WRITE to the last (READ - 1 wrapped) 25097ac9a364SKalle Valo * 25107ac9a364SKalle Valo * When the firmware places a packet in a buffer, it will advance the READ idx 25117ac9a364SKalle Valo * and fire the RX interrupt. The driver can then query the READ idx and 25127ac9a364SKalle Valo * process as many packets as possible, moving the WRITE idx forward as it 25137ac9a364SKalle Valo * resets the Rx queue buffers with new memory. 25147ac9a364SKalle Valo * 25157ac9a364SKalle Valo * The management in the driver is as follows: 25167ac9a364SKalle Valo * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When 25177ac9a364SKalle Valo * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled 25187ac9a364SKalle Valo * to replenish the iwl->rxq->rx_free. 25197ac9a364SKalle Valo * + In il_rx_replenish (scheduled) if 'processed' != 'read' then the 25207ac9a364SKalle Valo * iwl->rxq is replenished and the READ IDX is updated (updating the 25217ac9a364SKalle Valo * 'processed' and 'read' driver idxes as well) 25227ac9a364SKalle Valo * + A received packet is processed and handed to the kernel network stack, 25237ac9a364SKalle Valo * detached from the iwl->rxq. The driver 'processed' idx is updated. 25247ac9a364SKalle Valo * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free 25257ac9a364SKalle Valo * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ 25267ac9a364SKalle Valo * IDX is not incremented and iwl->status(RX_STALLED) is set. If there 25277ac9a364SKalle Valo * were enough free buffers and RX_STALLED is set it is cleared. 25287ac9a364SKalle Valo * 25297ac9a364SKalle Valo * 25307ac9a364SKalle Valo * Driver sequence: 25317ac9a364SKalle Valo * 25327ac9a364SKalle Valo * il_rx_queue_alloc() Allocates rx_free 25337ac9a364SKalle Valo * il_rx_replenish() Replenishes rx_free list from rx_used, and calls 25347ac9a364SKalle Valo * il_rx_queue_restock 25357ac9a364SKalle Valo * il_rx_queue_restock() Moves available buffers from rx_free into Rx 25367ac9a364SKalle Valo * queue, updates firmware pointers, and updates 25377ac9a364SKalle Valo * the WRITE idx. If insufficient rx_free buffers 25387ac9a364SKalle Valo * are available, schedules il_rx_replenish 25397ac9a364SKalle Valo * 25407ac9a364SKalle Valo * -- enable interrupts -- 25417ac9a364SKalle Valo * ISR - il_rx() Detach il_rx_bufs from pool up to the 25427ac9a364SKalle Valo * READ IDX, detaching the SKB from the pool. 25437ac9a364SKalle Valo * Moves the packet buffer from queue to rx_used. 25447ac9a364SKalle Valo * Calls il_rx_queue_restock to refill any empty 25457ac9a364SKalle Valo * slots. 25467ac9a364SKalle Valo * ... 25477ac9a364SKalle Valo * 25487ac9a364SKalle Valo */ 25497ac9a364SKalle Valo 25507ac9a364SKalle Valo /** 25517ac9a364SKalle Valo * il_rx_queue_space - Return number of free slots available in queue. 25527ac9a364SKalle Valo */ 25537ac9a364SKalle Valo int 25547ac9a364SKalle Valo il_rx_queue_space(const struct il_rx_queue *q) 25557ac9a364SKalle Valo { 25567ac9a364SKalle Valo int s = q->read - q->write; 25577ac9a364SKalle Valo if (s <= 0) 25587ac9a364SKalle Valo s += RX_QUEUE_SIZE; 25597ac9a364SKalle Valo /* keep some buffer to not confuse full and empty queue */ 25607ac9a364SKalle Valo s -= 2; 25617ac9a364SKalle Valo if (s < 0) 25627ac9a364SKalle Valo s = 0; 25637ac9a364SKalle Valo return s; 25647ac9a364SKalle Valo } 25657ac9a364SKalle Valo EXPORT_SYMBOL(il_rx_queue_space); 25667ac9a364SKalle Valo 25677ac9a364SKalle Valo /** 25687ac9a364SKalle Valo * il_rx_queue_update_write_ptr - Update the write pointer for the RX queue 25697ac9a364SKalle Valo */ 25707ac9a364SKalle Valo void 25717ac9a364SKalle Valo il_rx_queue_update_write_ptr(struct il_priv *il, struct il_rx_queue *q) 25727ac9a364SKalle Valo { 25737ac9a364SKalle Valo unsigned long flags; 25747ac9a364SKalle Valo u32 rx_wrt_ptr_reg = il->hw_params.rx_wrt_ptr_reg; 25757ac9a364SKalle Valo u32 reg; 25767ac9a364SKalle Valo 25777ac9a364SKalle Valo spin_lock_irqsave(&q->lock, flags); 25787ac9a364SKalle Valo 25797ac9a364SKalle Valo if (q->need_update == 0) 25807ac9a364SKalle Valo goto exit_unlock; 25817ac9a364SKalle Valo 25827ac9a364SKalle Valo /* If power-saving is in use, make sure device is awake */ 25837ac9a364SKalle Valo if (test_bit(S_POWER_PMI, &il->status)) { 25847ac9a364SKalle Valo reg = _il_rd(il, CSR_UCODE_DRV_GP1); 25857ac9a364SKalle Valo 25867ac9a364SKalle Valo if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { 25877ac9a364SKalle Valo D_INFO("Rx queue requesting wakeup," " GP1 = 0x%x\n", 25887ac9a364SKalle Valo reg); 25897ac9a364SKalle Valo il_set_bit(il, CSR_GP_CNTRL, 25907ac9a364SKalle Valo CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 25917ac9a364SKalle Valo goto exit_unlock; 25927ac9a364SKalle Valo } 25937ac9a364SKalle Valo 25947ac9a364SKalle Valo q->write_actual = (q->write & ~0x7); 25957ac9a364SKalle Valo il_wr(il, rx_wrt_ptr_reg, q->write_actual); 25967ac9a364SKalle Valo 25977ac9a364SKalle Valo /* Else device is assumed to be awake */ 25987ac9a364SKalle Valo } else { 25997ac9a364SKalle Valo /* Device expects a multiple of 8 */ 26007ac9a364SKalle Valo q->write_actual = (q->write & ~0x7); 26017ac9a364SKalle Valo il_wr(il, rx_wrt_ptr_reg, q->write_actual); 26027ac9a364SKalle Valo } 26037ac9a364SKalle Valo 26047ac9a364SKalle Valo q->need_update = 0; 26057ac9a364SKalle Valo 26067ac9a364SKalle Valo exit_unlock: 26077ac9a364SKalle Valo spin_unlock_irqrestore(&q->lock, flags); 26087ac9a364SKalle Valo } 26097ac9a364SKalle Valo EXPORT_SYMBOL(il_rx_queue_update_write_ptr); 26107ac9a364SKalle Valo 26117ac9a364SKalle Valo int 26127ac9a364SKalle Valo il_rx_queue_alloc(struct il_priv *il) 26137ac9a364SKalle Valo { 26147ac9a364SKalle Valo struct il_rx_queue *rxq = &il->rxq; 26157ac9a364SKalle Valo struct device *dev = &il->pci_dev->dev; 26167ac9a364SKalle Valo int i; 26177ac9a364SKalle Valo 26187ac9a364SKalle Valo spin_lock_init(&rxq->lock); 26197ac9a364SKalle Valo INIT_LIST_HEAD(&rxq->rx_free); 26207ac9a364SKalle Valo INIT_LIST_HEAD(&rxq->rx_used); 26217ac9a364SKalle Valo 26227ac9a364SKalle Valo /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ 26237ac9a364SKalle Valo rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma, 26247ac9a364SKalle Valo GFP_KERNEL); 26257ac9a364SKalle Valo if (!rxq->bd) 26267ac9a364SKalle Valo goto err_bd; 26277ac9a364SKalle Valo 26287ac9a364SKalle Valo rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct il_rb_status), 26297ac9a364SKalle Valo &rxq->rb_stts_dma, GFP_KERNEL); 26307ac9a364SKalle Valo if (!rxq->rb_stts) 26317ac9a364SKalle Valo goto err_rb; 26327ac9a364SKalle Valo 26337ac9a364SKalle Valo /* Fill the rx_used queue with _all_ of the Rx buffers */ 26347ac9a364SKalle Valo for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) 26357ac9a364SKalle Valo list_add_tail(&rxq->pool[i].list, &rxq->rx_used); 26367ac9a364SKalle Valo 26377ac9a364SKalle Valo /* Set us so that we have processed and used all buffers, but have 26387ac9a364SKalle Valo * not restocked the Rx queue with fresh buffers */ 26397ac9a364SKalle Valo rxq->read = rxq->write = 0; 26407ac9a364SKalle Valo rxq->write_actual = 0; 26417ac9a364SKalle Valo rxq->free_count = 0; 26427ac9a364SKalle Valo rxq->need_update = 0; 26437ac9a364SKalle Valo return 0; 26447ac9a364SKalle Valo 26457ac9a364SKalle Valo err_rb: 26467ac9a364SKalle Valo dma_free_coherent(&il->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd, 26477ac9a364SKalle Valo rxq->bd_dma); 26487ac9a364SKalle Valo err_bd: 26497ac9a364SKalle Valo return -ENOMEM; 26507ac9a364SKalle Valo } 26517ac9a364SKalle Valo EXPORT_SYMBOL(il_rx_queue_alloc); 26527ac9a364SKalle Valo 26537ac9a364SKalle Valo void 26547ac9a364SKalle Valo il_hdl_spectrum_measurement(struct il_priv *il, struct il_rx_buf *rxb) 26557ac9a364SKalle Valo { 26567ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 26577ac9a364SKalle Valo struct il_spectrum_notification *report = &(pkt->u.spectrum_notif); 26587ac9a364SKalle Valo 26597ac9a364SKalle Valo if (!report->state) { 26607ac9a364SKalle Valo D_11H("Spectrum Measure Notification: Start\n"); 26617ac9a364SKalle Valo return; 26627ac9a364SKalle Valo } 26637ac9a364SKalle Valo 26647ac9a364SKalle Valo memcpy(&il->measure_report, report, sizeof(*report)); 26657ac9a364SKalle Valo il->measurement_status |= MEASUREMENT_READY; 26667ac9a364SKalle Valo } 26677ac9a364SKalle Valo EXPORT_SYMBOL(il_hdl_spectrum_measurement); 26687ac9a364SKalle Valo 26697ac9a364SKalle Valo /* 26707ac9a364SKalle Valo * returns non-zero if packet should be dropped 26717ac9a364SKalle Valo */ 26727ac9a364SKalle Valo int 26737ac9a364SKalle Valo il_set_decrypted_flag(struct il_priv *il, struct ieee80211_hdr *hdr, 26747ac9a364SKalle Valo u32 decrypt_res, struct ieee80211_rx_status *stats) 26757ac9a364SKalle Valo { 26767ac9a364SKalle Valo u16 fc = le16_to_cpu(hdr->frame_control); 26777ac9a364SKalle Valo 26787ac9a364SKalle Valo /* 26797ac9a364SKalle Valo * All contexts have the same setting here due to it being 26807ac9a364SKalle Valo * a module parameter, so OK to check any context. 26817ac9a364SKalle Valo */ 26827ac9a364SKalle Valo if (il->active.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) 26837ac9a364SKalle Valo return 0; 26847ac9a364SKalle Valo 26857ac9a364SKalle Valo if (!(fc & IEEE80211_FCTL_PROTECTED)) 26867ac9a364SKalle Valo return 0; 26877ac9a364SKalle Valo 26887ac9a364SKalle Valo D_RX("decrypt_res:0x%x\n", decrypt_res); 26897ac9a364SKalle Valo switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { 26907ac9a364SKalle Valo case RX_RES_STATUS_SEC_TYPE_TKIP: 26917ac9a364SKalle Valo /* The uCode has got a bad phase 1 Key, pushes the packet. 26927ac9a364SKalle Valo * Decryption will be done in SW. */ 26937ac9a364SKalle Valo if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 26947ac9a364SKalle Valo RX_RES_STATUS_BAD_KEY_TTAK) 26957ac9a364SKalle Valo break; 26967ac9a364SKalle Valo 26977ac9a364SKalle Valo case RX_RES_STATUS_SEC_TYPE_WEP: 26987ac9a364SKalle Valo if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 26997ac9a364SKalle Valo RX_RES_STATUS_BAD_ICV_MIC) { 27007ac9a364SKalle Valo /* bad ICV, the packet is destroyed since the 27017ac9a364SKalle Valo * decryption is inplace, drop it */ 27027ac9a364SKalle Valo D_RX("Packet destroyed\n"); 27037ac9a364SKalle Valo return -1; 27047ac9a364SKalle Valo } 27057ac9a364SKalle Valo case RX_RES_STATUS_SEC_TYPE_CCMP: 27067ac9a364SKalle Valo if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == 27077ac9a364SKalle Valo RX_RES_STATUS_DECRYPT_OK) { 27087ac9a364SKalle Valo D_RX("hw decrypt successfully!!!\n"); 27097ac9a364SKalle Valo stats->flag |= RX_FLAG_DECRYPTED; 27107ac9a364SKalle Valo } 27117ac9a364SKalle Valo break; 27127ac9a364SKalle Valo 27137ac9a364SKalle Valo default: 27147ac9a364SKalle Valo break; 27157ac9a364SKalle Valo } 27167ac9a364SKalle Valo return 0; 27177ac9a364SKalle Valo } 27187ac9a364SKalle Valo EXPORT_SYMBOL(il_set_decrypted_flag); 27197ac9a364SKalle Valo 27207ac9a364SKalle Valo /** 27217ac9a364SKalle Valo * il_txq_update_write_ptr - Send new write idx to hardware 27227ac9a364SKalle Valo */ 27237ac9a364SKalle Valo void 27247ac9a364SKalle Valo il_txq_update_write_ptr(struct il_priv *il, struct il_tx_queue *txq) 27257ac9a364SKalle Valo { 27267ac9a364SKalle Valo u32 reg = 0; 27277ac9a364SKalle Valo int txq_id = txq->q.id; 27287ac9a364SKalle Valo 27297ac9a364SKalle Valo if (txq->need_update == 0) 27307ac9a364SKalle Valo return; 27317ac9a364SKalle Valo 27327ac9a364SKalle Valo /* if we're trying to save power */ 27337ac9a364SKalle Valo if (test_bit(S_POWER_PMI, &il->status)) { 27347ac9a364SKalle Valo /* wake up nic if it's powered down ... 27357ac9a364SKalle Valo * uCode will wake up, and interrupt us again, so next 27367ac9a364SKalle Valo * time we'll skip this part. */ 27377ac9a364SKalle Valo reg = _il_rd(il, CSR_UCODE_DRV_GP1); 27387ac9a364SKalle Valo 27397ac9a364SKalle Valo if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { 27407ac9a364SKalle Valo D_INFO("Tx queue %d requesting wakeup," " GP1 = 0x%x\n", 27417ac9a364SKalle Valo txq_id, reg); 27427ac9a364SKalle Valo il_set_bit(il, CSR_GP_CNTRL, 27437ac9a364SKalle Valo CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 27447ac9a364SKalle Valo return; 27457ac9a364SKalle Valo } 27467ac9a364SKalle Valo 27477ac9a364SKalle Valo il_wr(il, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); 27487ac9a364SKalle Valo 27497ac9a364SKalle Valo /* 27507ac9a364SKalle Valo * else not in power-save mode, 27517ac9a364SKalle Valo * uCode will never sleep when we're 27527ac9a364SKalle Valo * trying to tx (during RFKILL, we're not trying to tx). 27537ac9a364SKalle Valo */ 27547ac9a364SKalle Valo } else 27557ac9a364SKalle Valo _il_wr(il, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); 27567ac9a364SKalle Valo txq->need_update = 0; 27577ac9a364SKalle Valo } 27587ac9a364SKalle Valo EXPORT_SYMBOL(il_txq_update_write_ptr); 27597ac9a364SKalle Valo 27607ac9a364SKalle Valo /** 27617ac9a364SKalle Valo * il_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's 27627ac9a364SKalle Valo */ 27637ac9a364SKalle Valo void 27647ac9a364SKalle Valo il_tx_queue_unmap(struct il_priv *il, int txq_id) 27657ac9a364SKalle Valo { 27667ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[txq_id]; 27677ac9a364SKalle Valo struct il_queue *q = &txq->q; 27687ac9a364SKalle Valo 27697ac9a364SKalle Valo if (q->n_bd == 0) 27707ac9a364SKalle Valo return; 27717ac9a364SKalle Valo 27727ac9a364SKalle Valo while (q->write_ptr != q->read_ptr) { 27737ac9a364SKalle Valo il->ops->txq_free_tfd(il, txq); 27747ac9a364SKalle Valo q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd); 27757ac9a364SKalle Valo } 27767ac9a364SKalle Valo } 27777ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_queue_unmap); 27787ac9a364SKalle Valo 27797ac9a364SKalle Valo /** 27807ac9a364SKalle Valo * il_tx_queue_free - Deallocate DMA queue. 27817ac9a364SKalle Valo * @txq: Transmit queue to deallocate. 27827ac9a364SKalle Valo * 27837ac9a364SKalle Valo * Empty queue by removing and destroying all BD's. 27847ac9a364SKalle Valo * Free all buffers. 27857ac9a364SKalle Valo * 0-fill, but do not free "txq" descriptor structure. 27867ac9a364SKalle Valo */ 27877ac9a364SKalle Valo void 27887ac9a364SKalle Valo il_tx_queue_free(struct il_priv *il, int txq_id) 27897ac9a364SKalle Valo { 27907ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[txq_id]; 27917ac9a364SKalle Valo struct device *dev = &il->pci_dev->dev; 27927ac9a364SKalle Valo int i; 27937ac9a364SKalle Valo 27947ac9a364SKalle Valo il_tx_queue_unmap(il, txq_id); 27957ac9a364SKalle Valo 27967ac9a364SKalle Valo /* De-alloc array of command/tx buffers */ 27977ac9a364SKalle Valo for (i = 0; i < TFD_TX_CMD_SLOTS; i++) 27987ac9a364SKalle Valo kfree(txq->cmd[i]); 27997ac9a364SKalle Valo 28007ac9a364SKalle Valo /* De-alloc circular buffer of TFDs */ 28017ac9a364SKalle Valo if (txq->q.n_bd) 28027ac9a364SKalle Valo dma_free_coherent(dev, il->hw_params.tfd_size * txq->q.n_bd, 28037ac9a364SKalle Valo txq->tfds, txq->q.dma_addr); 28047ac9a364SKalle Valo 28057ac9a364SKalle Valo /* De-alloc array of per-TFD driver data */ 28067ac9a364SKalle Valo kfree(txq->skbs); 28077ac9a364SKalle Valo txq->skbs = NULL; 28087ac9a364SKalle Valo 28097ac9a364SKalle Valo /* deallocate arrays */ 28107ac9a364SKalle Valo kfree(txq->cmd); 28117ac9a364SKalle Valo kfree(txq->meta); 28127ac9a364SKalle Valo txq->cmd = NULL; 28137ac9a364SKalle Valo txq->meta = NULL; 28147ac9a364SKalle Valo 28157ac9a364SKalle Valo /* 0-fill queue descriptor structure */ 28167ac9a364SKalle Valo memset(txq, 0, sizeof(*txq)); 28177ac9a364SKalle Valo } 28187ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_queue_free); 28197ac9a364SKalle Valo 28207ac9a364SKalle Valo /** 28217ac9a364SKalle Valo * il_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue 28227ac9a364SKalle Valo */ 28237ac9a364SKalle Valo void 28247ac9a364SKalle Valo il_cmd_queue_unmap(struct il_priv *il) 28257ac9a364SKalle Valo { 28267ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[il->cmd_queue]; 28277ac9a364SKalle Valo struct il_queue *q = &txq->q; 28287ac9a364SKalle Valo int i; 28297ac9a364SKalle Valo 28307ac9a364SKalle Valo if (q->n_bd == 0) 28317ac9a364SKalle Valo return; 28327ac9a364SKalle Valo 28337ac9a364SKalle Valo while (q->read_ptr != q->write_ptr) { 28347ac9a364SKalle Valo i = il_get_cmd_idx(q, q->read_ptr, 0); 28357ac9a364SKalle Valo 28367ac9a364SKalle Valo if (txq->meta[i].flags & CMD_MAPPED) { 28377ac9a364SKalle Valo pci_unmap_single(il->pci_dev, 28387ac9a364SKalle Valo dma_unmap_addr(&txq->meta[i], mapping), 28397ac9a364SKalle Valo dma_unmap_len(&txq->meta[i], len), 28407ac9a364SKalle Valo PCI_DMA_BIDIRECTIONAL); 28417ac9a364SKalle Valo txq->meta[i].flags = 0; 28427ac9a364SKalle Valo } 28437ac9a364SKalle Valo 28447ac9a364SKalle Valo q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd); 28457ac9a364SKalle Valo } 28467ac9a364SKalle Valo 28477ac9a364SKalle Valo i = q->n_win; 28487ac9a364SKalle Valo if (txq->meta[i].flags & CMD_MAPPED) { 28497ac9a364SKalle Valo pci_unmap_single(il->pci_dev, 28507ac9a364SKalle Valo dma_unmap_addr(&txq->meta[i], mapping), 28517ac9a364SKalle Valo dma_unmap_len(&txq->meta[i], len), 28527ac9a364SKalle Valo PCI_DMA_BIDIRECTIONAL); 28537ac9a364SKalle Valo txq->meta[i].flags = 0; 28547ac9a364SKalle Valo } 28557ac9a364SKalle Valo } 28567ac9a364SKalle Valo EXPORT_SYMBOL(il_cmd_queue_unmap); 28577ac9a364SKalle Valo 28587ac9a364SKalle Valo /** 28597ac9a364SKalle Valo * il_cmd_queue_free - Deallocate DMA queue. 28607ac9a364SKalle Valo * @txq: Transmit queue to deallocate. 28617ac9a364SKalle Valo * 28627ac9a364SKalle Valo * Empty queue by removing and destroying all BD's. 28637ac9a364SKalle Valo * Free all buffers. 28647ac9a364SKalle Valo * 0-fill, but do not free "txq" descriptor structure. 28657ac9a364SKalle Valo */ 28667ac9a364SKalle Valo void 28677ac9a364SKalle Valo il_cmd_queue_free(struct il_priv *il) 28687ac9a364SKalle Valo { 28697ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[il->cmd_queue]; 28707ac9a364SKalle Valo struct device *dev = &il->pci_dev->dev; 28717ac9a364SKalle Valo int i; 28727ac9a364SKalle Valo 28737ac9a364SKalle Valo il_cmd_queue_unmap(il); 28747ac9a364SKalle Valo 28757ac9a364SKalle Valo /* De-alloc array of command/tx buffers */ 28767ac9a364SKalle Valo for (i = 0; i <= TFD_CMD_SLOTS; i++) 28777ac9a364SKalle Valo kfree(txq->cmd[i]); 28787ac9a364SKalle Valo 28797ac9a364SKalle Valo /* De-alloc circular buffer of TFDs */ 28807ac9a364SKalle Valo if (txq->q.n_bd) 28817ac9a364SKalle Valo dma_free_coherent(dev, il->hw_params.tfd_size * txq->q.n_bd, 28827ac9a364SKalle Valo txq->tfds, txq->q.dma_addr); 28837ac9a364SKalle Valo 28847ac9a364SKalle Valo /* deallocate arrays */ 28857ac9a364SKalle Valo kfree(txq->cmd); 28867ac9a364SKalle Valo kfree(txq->meta); 28877ac9a364SKalle Valo txq->cmd = NULL; 28887ac9a364SKalle Valo txq->meta = NULL; 28897ac9a364SKalle Valo 28907ac9a364SKalle Valo /* 0-fill queue descriptor structure */ 28917ac9a364SKalle Valo memset(txq, 0, sizeof(*txq)); 28927ac9a364SKalle Valo } 28937ac9a364SKalle Valo EXPORT_SYMBOL(il_cmd_queue_free); 28947ac9a364SKalle Valo 28957ac9a364SKalle Valo /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** 28967ac9a364SKalle Valo * DMA services 28977ac9a364SKalle Valo * 28987ac9a364SKalle Valo * Theory of operation 28997ac9a364SKalle Valo * 29007ac9a364SKalle Valo * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer 29017ac9a364SKalle Valo * of buffer descriptors, each of which points to one or more data buffers for 29027ac9a364SKalle Valo * the device to read from or fill. Driver and device exchange status of each 29037ac9a364SKalle Valo * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty 29047ac9a364SKalle Valo * entries in each circular buffer, to protect against confusing empty and full 29057ac9a364SKalle Valo * queue states. 29067ac9a364SKalle Valo * 29077ac9a364SKalle Valo * The device reads or writes the data in the queues via the device's several 29087ac9a364SKalle Valo * DMA/FIFO channels. Each queue is mapped to a single DMA channel. 29097ac9a364SKalle Valo * 29107ac9a364SKalle Valo * For Tx queue, there are low mark and high mark limits. If, after queuing 29117ac9a364SKalle Valo * the packet for Tx, free space become < low mark, Tx queue stopped. When 29127ac9a364SKalle Valo * reclaiming packets (on 'tx done IRQ), if free space become > high mark, 29137ac9a364SKalle Valo * Tx queue resumed. 29147ac9a364SKalle Valo * 29157ac9a364SKalle Valo * See more detailed info in 4965.h. 29167ac9a364SKalle Valo ***************************************************/ 29177ac9a364SKalle Valo 29187ac9a364SKalle Valo int 29197ac9a364SKalle Valo il_queue_space(const struct il_queue *q) 29207ac9a364SKalle Valo { 29217ac9a364SKalle Valo int s = q->read_ptr - q->write_ptr; 29227ac9a364SKalle Valo 29237ac9a364SKalle Valo if (q->read_ptr > q->write_ptr) 29247ac9a364SKalle Valo s -= q->n_bd; 29257ac9a364SKalle Valo 29267ac9a364SKalle Valo if (s <= 0) 29277ac9a364SKalle Valo s += q->n_win; 29287ac9a364SKalle Valo /* keep some reserve to not confuse empty and full situations */ 29297ac9a364SKalle Valo s -= 2; 29307ac9a364SKalle Valo if (s < 0) 29317ac9a364SKalle Valo s = 0; 29327ac9a364SKalle Valo return s; 29337ac9a364SKalle Valo } 29347ac9a364SKalle Valo EXPORT_SYMBOL(il_queue_space); 29357ac9a364SKalle Valo 29367ac9a364SKalle Valo 29377ac9a364SKalle Valo /** 29387ac9a364SKalle Valo * il_queue_init - Initialize queue's high/low-water and read/write idxes 29397ac9a364SKalle Valo */ 29407ac9a364SKalle Valo static int 29417ac9a364SKalle Valo il_queue_init(struct il_priv *il, struct il_queue *q, int slots, u32 id) 29427ac9a364SKalle Valo { 29437ac9a364SKalle Valo /* 29447ac9a364SKalle Valo * TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise 29457ac9a364SKalle Valo * il_queue_inc_wrap and il_queue_dec_wrap are broken. 29467ac9a364SKalle Valo */ 29477ac9a364SKalle Valo BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); 29487ac9a364SKalle Valo /* FIXME: remove q->n_bd */ 29497ac9a364SKalle Valo q->n_bd = TFD_QUEUE_SIZE_MAX; 29507ac9a364SKalle Valo 29517ac9a364SKalle Valo q->n_win = slots; 29527ac9a364SKalle Valo q->id = id; 29537ac9a364SKalle Valo 29547ac9a364SKalle Valo /* slots_must be power-of-two size, otherwise 29557ac9a364SKalle Valo * il_get_cmd_idx is broken. */ 29567ac9a364SKalle Valo BUG_ON(!is_power_of_2(slots)); 29577ac9a364SKalle Valo 29587ac9a364SKalle Valo q->low_mark = q->n_win / 4; 29597ac9a364SKalle Valo if (q->low_mark < 4) 29607ac9a364SKalle Valo q->low_mark = 4; 29617ac9a364SKalle Valo 29627ac9a364SKalle Valo q->high_mark = q->n_win / 8; 29637ac9a364SKalle Valo if (q->high_mark < 2) 29647ac9a364SKalle Valo q->high_mark = 2; 29657ac9a364SKalle Valo 29667ac9a364SKalle Valo q->write_ptr = q->read_ptr = 0; 29677ac9a364SKalle Valo 29687ac9a364SKalle Valo return 0; 29697ac9a364SKalle Valo } 29707ac9a364SKalle Valo 29717ac9a364SKalle Valo /** 29727ac9a364SKalle Valo * il_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue 29737ac9a364SKalle Valo */ 29747ac9a364SKalle Valo static int 29757ac9a364SKalle Valo il_tx_queue_alloc(struct il_priv *il, struct il_tx_queue *txq, u32 id) 29767ac9a364SKalle Valo { 29777ac9a364SKalle Valo struct device *dev = &il->pci_dev->dev; 29787ac9a364SKalle Valo size_t tfd_sz = il->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; 29797ac9a364SKalle Valo 29807ac9a364SKalle Valo /* Driver ilate data, only for Tx (not command) queues, 29817ac9a364SKalle Valo * not shared with device. */ 29827ac9a364SKalle Valo if (id != il->cmd_queue) { 29837ac9a364SKalle Valo txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, 29847ac9a364SKalle Valo sizeof(struct sk_buff *), 29857ac9a364SKalle Valo GFP_KERNEL); 29867ac9a364SKalle Valo if (!txq->skbs) { 29877ac9a364SKalle Valo IL_ERR("Fail to alloc skbs\n"); 29887ac9a364SKalle Valo goto error; 29897ac9a364SKalle Valo } 29907ac9a364SKalle Valo } else 29917ac9a364SKalle Valo txq->skbs = NULL; 29927ac9a364SKalle Valo 29937ac9a364SKalle Valo /* Circular buffer of transmit frame descriptors (TFDs), 29947ac9a364SKalle Valo * shared with device */ 29957ac9a364SKalle Valo txq->tfds = 29967ac9a364SKalle Valo dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr, GFP_KERNEL); 29977ac9a364SKalle Valo if (!txq->tfds) 29987ac9a364SKalle Valo goto error; 29997ac9a364SKalle Valo 30007ac9a364SKalle Valo txq->q.id = id; 30017ac9a364SKalle Valo 30027ac9a364SKalle Valo return 0; 30037ac9a364SKalle Valo 30047ac9a364SKalle Valo error: 30057ac9a364SKalle Valo kfree(txq->skbs); 30067ac9a364SKalle Valo txq->skbs = NULL; 30077ac9a364SKalle Valo 30087ac9a364SKalle Valo return -ENOMEM; 30097ac9a364SKalle Valo } 30107ac9a364SKalle Valo 30117ac9a364SKalle Valo /** 30127ac9a364SKalle Valo * il_tx_queue_init - Allocate and initialize one tx/cmd queue 30137ac9a364SKalle Valo */ 30147ac9a364SKalle Valo int 30157ac9a364SKalle Valo il_tx_queue_init(struct il_priv *il, u32 txq_id) 30167ac9a364SKalle Valo { 30177ac9a364SKalle Valo int i, len, ret; 30187ac9a364SKalle Valo int slots, actual_slots; 30197ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[txq_id]; 30207ac9a364SKalle Valo 30217ac9a364SKalle Valo /* 30227ac9a364SKalle Valo * Alloc buffer array for commands (Tx or other types of commands). 30237ac9a364SKalle Valo * For the command queue (#4/#9), allocate command space + one big 30247ac9a364SKalle Valo * command for scan, since scan command is very huge; the system will 30257ac9a364SKalle Valo * not have two scans at the same time, so only one is needed. 30267ac9a364SKalle Valo * For normal Tx queues (all other queues), no super-size command 30277ac9a364SKalle Valo * space is needed. 30287ac9a364SKalle Valo */ 30297ac9a364SKalle Valo if (txq_id == il->cmd_queue) { 30307ac9a364SKalle Valo slots = TFD_CMD_SLOTS; 30317ac9a364SKalle Valo actual_slots = slots + 1; 30327ac9a364SKalle Valo } else { 30337ac9a364SKalle Valo slots = TFD_TX_CMD_SLOTS; 30347ac9a364SKalle Valo actual_slots = slots; 30357ac9a364SKalle Valo } 30367ac9a364SKalle Valo 30377ac9a364SKalle Valo txq->meta = 30387ac9a364SKalle Valo kzalloc(sizeof(struct il_cmd_meta) * actual_slots, GFP_KERNEL); 30397ac9a364SKalle Valo txq->cmd = 30407ac9a364SKalle Valo kzalloc(sizeof(struct il_device_cmd *) * actual_slots, GFP_KERNEL); 30417ac9a364SKalle Valo 30427ac9a364SKalle Valo if (!txq->meta || !txq->cmd) 30437ac9a364SKalle Valo goto out_free_arrays; 30447ac9a364SKalle Valo 30457ac9a364SKalle Valo len = sizeof(struct il_device_cmd); 30467ac9a364SKalle Valo for (i = 0; i < actual_slots; i++) { 30477ac9a364SKalle Valo /* only happens for cmd queue */ 30487ac9a364SKalle Valo if (i == slots) 30497ac9a364SKalle Valo len = IL_MAX_CMD_SIZE; 30507ac9a364SKalle Valo 30517ac9a364SKalle Valo txq->cmd[i] = kmalloc(len, GFP_KERNEL); 30527ac9a364SKalle Valo if (!txq->cmd[i]) 30537ac9a364SKalle Valo goto err; 30547ac9a364SKalle Valo } 30557ac9a364SKalle Valo 30567ac9a364SKalle Valo /* Alloc driver data array and TFD circular buffer */ 30577ac9a364SKalle Valo ret = il_tx_queue_alloc(il, txq, txq_id); 30587ac9a364SKalle Valo if (ret) 30597ac9a364SKalle Valo goto err; 30607ac9a364SKalle Valo 30617ac9a364SKalle Valo txq->need_update = 0; 30627ac9a364SKalle Valo 30637ac9a364SKalle Valo /* 30647ac9a364SKalle Valo * For the default queues 0-3, set up the swq_id 30657ac9a364SKalle Valo * already -- all others need to get one later 30667ac9a364SKalle Valo * (if they need one at all). 30677ac9a364SKalle Valo */ 30687ac9a364SKalle Valo if (txq_id < 4) 30697ac9a364SKalle Valo il_set_swq_id(txq, txq_id, txq_id); 30707ac9a364SKalle Valo 30717ac9a364SKalle Valo /* Initialize queue's high/low-water marks, and head/tail idxes */ 30727ac9a364SKalle Valo il_queue_init(il, &txq->q, slots, txq_id); 30737ac9a364SKalle Valo 30747ac9a364SKalle Valo /* Tell device where to find queue */ 30757ac9a364SKalle Valo il->ops->txq_init(il, txq); 30767ac9a364SKalle Valo 30777ac9a364SKalle Valo return 0; 30787ac9a364SKalle Valo err: 30797ac9a364SKalle Valo for (i = 0; i < actual_slots; i++) 30807ac9a364SKalle Valo kfree(txq->cmd[i]); 30817ac9a364SKalle Valo out_free_arrays: 30827ac9a364SKalle Valo kfree(txq->meta); 30837ac9a364SKalle Valo kfree(txq->cmd); 30847ac9a364SKalle Valo 30857ac9a364SKalle Valo return -ENOMEM; 30867ac9a364SKalle Valo } 30877ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_queue_init); 30887ac9a364SKalle Valo 30897ac9a364SKalle Valo void 30907ac9a364SKalle Valo il_tx_queue_reset(struct il_priv *il, u32 txq_id) 30917ac9a364SKalle Valo { 30927ac9a364SKalle Valo int slots, actual_slots; 30937ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[txq_id]; 30947ac9a364SKalle Valo 30957ac9a364SKalle Valo if (txq_id == il->cmd_queue) { 30967ac9a364SKalle Valo slots = TFD_CMD_SLOTS; 30977ac9a364SKalle Valo actual_slots = TFD_CMD_SLOTS + 1; 30987ac9a364SKalle Valo } else { 30997ac9a364SKalle Valo slots = TFD_TX_CMD_SLOTS; 31007ac9a364SKalle Valo actual_slots = TFD_TX_CMD_SLOTS; 31017ac9a364SKalle Valo } 31027ac9a364SKalle Valo 31037ac9a364SKalle Valo memset(txq->meta, 0, sizeof(struct il_cmd_meta) * actual_slots); 31047ac9a364SKalle Valo txq->need_update = 0; 31057ac9a364SKalle Valo 31067ac9a364SKalle Valo /* Initialize queue's high/low-water marks, and head/tail idxes */ 31077ac9a364SKalle Valo il_queue_init(il, &txq->q, slots, txq_id); 31087ac9a364SKalle Valo 31097ac9a364SKalle Valo /* Tell device where to find queue */ 31107ac9a364SKalle Valo il->ops->txq_init(il, txq); 31117ac9a364SKalle Valo } 31127ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_queue_reset); 31137ac9a364SKalle Valo 31147ac9a364SKalle Valo /*************** HOST COMMAND QUEUE FUNCTIONS *****/ 31157ac9a364SKalle Valo 31167ac9a364SKalle Valo /** 31177ac9a364SKalle Valo * il_enqueue_hcmd - enqueue a uCode command 31187ac9a364SKalle Valo * @il: device ilate data point 31197ac9a364SKalle Valo * @cmd: a point to the ucode command structure 31207ac9a364SKalle Valo * 31217ac9a364SKalle Valo * The function returns < 0 values to indicate the operation is 31227ac9a364SKalle Valo * failed. On success, it turns the idx (> 0) of command in the 31237ac9a364SKalle Valo * command queue. 31247ac9a364SKalle Valo */ 31257ac9a364SKalle Valo int 31267ac9a364SKalle Valo il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) 31277ac9a364SKalle Valo { 31287ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[il->cmd_queue]; 31297ac9a364SKalle Valo struct il_queue *q = &txq->q; 31307ac9a364SKalle Valo struct il_device_cmd *out_cmd; 31317ac9a364SKalle Valo struct il_cmd_meta *out_meta; 31327ac9a364SKalle Valo dma_addr_t phys_addr; 31337ac9a364SKalle Valo unsigned long flags; 31347ac9a364SKalle Valo int len; 31357ac9a364SKalle Valo u32 idx; 31367ac9a364SKalle Valo u16 fix_size; 31377ac9a364SKalle Valo 31387ac9a364SKalle Valo cmd->len = il->ops->get_hcmd_size(cmd->id, cmd->len); 31397ac9a364SKalle Valo fix_size = (u16) (cmd->len + sizeof(out_cmd->hdr)); 31407ac9a364SKalle Valo 31417ac9a364SKalle Valo /* If any of the command structures end up being larger than 31427ac9a364SKalle Valo * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then 31437ac9a364SKalle Valo * we will need to increase the size of the TFD entries 31447ac9a364SKalle Valo * Also, check to see if command buffer should not exceed the size 31457ac9a364SKalle Valo * of device_cmd and max_cmd_size. */ 31467ac9a364SKalle Valo BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && 31477ac9a364SKalle Valo !(cmd->flags & CMD_SIZE_HUGE)); 31487ac9a364SKalle Valo BUG_ON(fix_size > IL_MAX_CMD_SIZE); 31497ac9a364SKalle Valo 31507ac9a364SKalle Valo if (il_is_rfkill(il) || il_is_ctkill(il)) { 31517ac9a364SKalle Valo IL_WARN("Not sending command - %s KILL\n", 31527ac9a364SKalle Valo il_is_rfkill(il) ? "RF" : "CT"); 31537ac9a364SKalle Valo return -EIO; 31547ac9a364SKalle Valo } 31557ac9a364SKalle Valo 31567ac9a364SKalle Valo spin_lock_irqsave(&il->hcmd_lock, flags); 31577ac9a364SKalle Valo 31587ac9a364SKalle Valo if (il_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { 31597ac9a364SKalle Valo spin_unlock_irqrestore(&il->hcmd_lock, flags); 31607ac9a364SKalle Valo 31617ac9a364SKalle Valo IL_ERR("Restarting adapter due to command queue full\n"); 31627ac9a364SKalle Valo queue_work(il->workqueue, &il->restart); 31637ac9a364SKalle Valo return -ENOSPC; 31647ac9a364SKalle Valo } 31657ac9a364SKalle Valo 31667ac9a364SKalle Valo idx = il_get_cmd_idx(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); 31677ac9a364SKalle Valo out_cmd = txq->cmd[idx]; 31687ac9a364SKalle Valo out_meta = &txq->meta[idx]; 31697ac9a364SKalle Valo 31707ac9a364SKalle Valo if (WARN_ON(out_meta->flags & CMD_MAPPED)) { 31717ac9a364SKalle Valo spin_unlock_irqrestore(&il->hcmd_lock, flags); 31727ac9a364SKalle Valo return -ENOSPC; 31737ac9a364SKalle Valo } 31747ac9a364SKalle Valo 31757ac9a364SKalle Valo memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ 31767ac9a364SKalle Valo out_meta->flags = cmd->flags | CMD_MAPPED; 31777ac9a364SKalle Valo if (cmd->flags & CMD_WANT_SKB) 31787ac9a364SKalle Valo out_meta->source = cmd; 31797ac9a364SKalle Valo if (cmd->flags & CMD_ASYNC) 31807ac9a364SKalle Valo out_meta->callback = cmd->callback; 31817ac9a364SKalle Valo 31827ac9a364SKalle Valo out_cmd->hdr.cmd = cmd->id; 31837ac9a364SKalle Valo memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); 31847ac9a364SKalle Valo 31857ac9a364SKalle Valo /* At this point, the out_cmd now has all of the incoming cmd 31867ac9a364SKalle Valo * information */ 31877ac9a364SKalle Valo 31887ac9a364SKalle Valo out_cmd->hdr.flags = 0; 31897ac9a364SKalle Valo out_cmd->hdr.sequence = 31907ac9a364SKalle Valo cpu_to_le16(QUEUE_TO_SEQ(il->cmd_queue) | IDX_TO_SEQ(q->write_ptr)); 31917ac9a364SKalle Valo if (cmd->flags & CMD_SIZE_HUGE) 31927ac9a364SKalle Valo out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; 31937ac9a364SKalle Valo len = sizeof(struct il_device_cmd); 31947ac9a364SKalle Valo if (idx == TFD_CMD_SLOTS) 31957ac9a364SKalle Valo len = IL_MAX_CMD_SIZE; 31967ac9a364SKalle Valo 31977ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 31987ac9a364SKalle Valo switch (out_cmd->hdr.cmd) { 31997ac9a364SKalle Valo case C_TX_LINK_QUALITY_CMD: 32007ac9a364SKalle Valo case C_SENSITIVITY: 32017ac9a364SKalle Valo D_HC_DUMP("Sending command %s (#%x), seq: 0x%04X, " 32027ac9a364SKalle Valo "%d bytes at %d[%d]:%d\n", 32037ac9a364SKalle Valo il_get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, 32047ac9a364SKalle Valo le16_to_cpu(out_cmd->hdr.sequence), fix_size, 32057ac9a364SKalle Valo q->write_ptr, idx, il->cmd_queue); 32067ac9a364SKalle Valo break; 32077ac9a364SKalle Valo default: 32087ac9a364SKalle Valo D_HC("Sending command %s (#%x), seq: 0x%04X, " 32097ac9a364SKalle Valo "%d bytes at %d[%d]:%d\n", 32107ac9a364SKalle Valo il_get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, 32117ac9a364SKalle Valo le16_to_cpu(out_cmd->hdr.sequence), fix_size, q->write_ptr, 32127ac9a364SKalle Valo idx, il->cmd_queue); 32137ac9a364SKalle Valo } 32147ac9a364SKalle Valo #endif 32157ac9a364SKalle Valo 32167ac9a364SKalle Valo phys_addr = 32177ac9a364SKalle Valo pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, 32187ac9a364SKalle Valo PCI_DMA_BIDIRECTIONAL); 32197ac9a364SKalle Valo if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) { 32207ac9a364SKalle Valo idx = -ENOMEM; 32217ac9a364SKalle Valo goto out; 32227ac9a364SKalle Valo } 32237ac9a364SKalle Valo dma_unmap_addr_set(out_meta, mapping, phys_addr); 32247ac9a364SKalle Valo dma_unmap_len_set(out_meta, len, fix_size); 32257ac9a364SKalle Valo 32267ac9a364SKalle Valo txq->need_update = 1; 32277ac9a364SKalle Valo 32287ac9a364SKalle Valo if (il->ops->txq_update_byte_cnt_tbl) 32297ac9a364SKalle Valo /* Set up entry in queue's byte count circular buffer */ 32307ac9a364SKalle Valo il->ops->txq_update_byte_cnt_tbl(il, txq, 0); 32317ac9a364SKalle Valo 32327ac9a364SKalle Valo il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, 32337ac9a364SKalle Valo U32_PAD(cmd->len)); 32347ac9a364SKalle Valo 32357ac9a364SKalle Valo /* Increment and update queue's write idx */ 32367ac9a364SKalle Valo q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); 32377ac9a364SKalle Valo il_txq_update_write_ptr(il, txq); 32387ac9a364SKalle Valo 32397ac9a364SKalle Valo out: 32407ac9a364SKalle Valo spin_unlock_irqrestore(&il->hcmd_lock, flags); 32417ac9a364SKalle Valo return idx; 32427ac9a364SKalle Valo } 32437ac9a364SKalle Valo 32447ac9a364SKalle Valo /** 32457ac9a364SKalle Valo * il_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd 32467ac9a364SKalle Valo * 32477ac9a364SKalle Valo * When FW advances 'R' idx, all entries between old and new 'R' idx 32487ac9a364SKalle Valo * need to be reclaimed. As result, some free space forms. If there is 32497ac9a364SKalle Valo * enough free space (> low mark), wake the stack that feeds us. 32507ac9a364SKalle Valo */ 32517ac9a364SKalle Valo static void 32527ac9a364SKalle Valo il_hcmd_queue_reclaim(struct il_priv *il, int txq_id, int idx, int cmd_idx) 32537ac9a364SKalle Valo { 32547ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[txq_id]; 32557ac9a364SKalle Valo struct il_queue *q = &txq->q; 32567ac9a364SKalle Valo int nfreed = 0; 32577ac9a364SKalle Valo 32587ac9a364SKalle Valo if (idx >= q->n_bd || il_queue_used(q, idx) == 0) { 32597ac9a364SKalle Valo IL_ERR("Read idx for DMA queue txq id (%d), idx %d, " 32607ac9a364SKalle Valo "is out of range [0-%d] %d %d.\n", txq_id, idx, q->n_bd, 32617ac9a364SKalle Valo q->write_ptr, q->read_ptr); 32627ac9a364SKalle Valo return; 32637ac9a364SKalle Valo } 32647ac9a364SKalle Valo 32657ac9a364SKalle Valo for (idx = il_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; 32667ac9a364SKalle Valo q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd)) { 32677ac9a364SKalle Valo 32687ac9a364SKalle Valo if (nfreed++ > 0) { 32697ac9a364SKalle Valo IL_ERR("HCMD skipped: idx (%d) %d %d\n", idx, 32707ac9a364SKalle Valo q->write_ptr, q->read_ptr); 32717ac9a364SKalle Valo queue_work(il->workqueue, &il->restart); 32727ac9a364SKalle Valo } 32737ac9a364SKalle Valo 32747ac9a364SKalle Valo } 32757ac9a364SKalle Valo } 32767ac9a364SKalle Valo 32777ac9a364SKalle Valo /** 32787ac9a364SKalle Valo * il_tx_cmd_complete - Pull unused buffers off the queue and reclaim them 32797ac9a364SKalle Valo * @rxb: Rx buffer to reclaim 32807ac9a364SKalle Valo * 32817ac9a364SKalle Valo * If an Rx buffer has an async callback associated with it the callback 32827ac9a364SKalle Valo * will be executed. The attached skb (if present) will only be freed 32837ac9a364SKalle Valo * if the callback returns 1 32847ac9a364SKalle Valo */ 32857ac9a364SKalle Valo void 32867ac9a364SKalle Valo il_tx_cmd_complete(struct il_priv *il, struct il_rx_buf *rxb) 32877ac9a364SKalle Valo { 32887ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 32897ac9a364SKalle Valo u16 sequence = le16_to_cpu(pkt->hdr.sequence); 32907ac9a364SKalle Valo int txq_id = SEQ_TO_QUEUE(sequence); 32917ac9a364SKalle Valo int idx = SEQ_TO_IDX(sequence); 32927ac9a364SKalle Valo int cmd_idx; 32937ac9a364SKalle Valo bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); 32947ac9a364SKalle Valo struct il_device_cmd *cmd; 32957ac9a364SKalle Valo struct il_cmd_meta *meta; 32967ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[il->cmd_queue]; 32977ac9a364SKalle Valo unsigned long flags; 32987ac9a364SKalle Valo 32997ac9a364SKalle Valo /* If a Tx command is being handled and it isn't in the actual 33007ac9a364SKalle Valo * command queue then there a command routing bug has been introduced 33017ac9a364SKalle Valo * in the queue management code. */ 33027ac9a364SKalle Valo if (WARN 33037ac9a364SKalle Valo (txq_id != il->cmd_queue, 33047ac9a364SKalle Valo "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n", 33057ac9a364SKalle Valo txq_id, il->cmd_queue, sequence, il->txq[il->cmd_queue].q.read_ptr, 33067ac9a364SKalle Valo il->txq[il->cmd_queue].q.write_ptr)) { 33077ac9a364SKalle Valo il_print_hex_error(il, pkt, 32); 33087ac9a364SKalle Valo return; 33097ac9a364SKalle Valo } 33107ac9a364SKalle Valo 33117ac9a364SKalle Valo cmd_idx = il_get_cmd_idx(&txq->q, idx, huge); 33127ac9a364SKalle Valo cmd = txq->cmd[cmd_idx]; 33137ac9a364SKalle Valo meta = &txq->meta[cmd_idx]; 33147ac9a364SKalle Valo 33157ac9a364SKalle Valo txq->time_stamp = jiffies; 33167ac9a364SKalle Valo 33177ac9a364SKalle Valo pci_unmap_single(il->pci_dev, dma_unmap_addr(meta, mapping), 33187ac9a364SKalle Valo dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); 33197ac9a364SKalle Valo 33207ac9a364SKalle Valo /* Input error checking is done when commands are added to queue. */ 33217ac9a364SKalle Valo if (meta->flags & CMD_WANT_SKB) { 33227ac9a364SKalle Valo meta->source->reply_page = (unsigned long)rxb_addr(rxb); 33237ac9a364SKalle Valo rxb->page = NULL; 33247ac9a364SKalle Valo } else if (meta->callback) 33257ac9a364SKalle Valo meta->callback(il, cmd, pkt); 33267ac9a364SKalle Valo 33277ac9a364SKalle Valo spin_lock_irqsave(&il->hcmd_lock, flags); 33287ac9a364SKalle Valo 33297ac9a364SKalle Valo il_hcmd_queue_reclaim(il, txq_id, idx, cmd_idx); 33307ac9a364SKalle Valo 33317ac9a364SKalle Valo if (!(meta->flags & CMD_ASYNC)) { 33327ac9a364SKalle Valo clear_bit(S_HCMD_ACTIVE, &il->status); 33337ac9a364SKalle Valo D_INFO("Clearing HCMD_ACTIVE for command %s\n", 33347ac9a364SKalle Valo il_get_cmd_string(cmd->hdr.cmd)); 33357ac9a364SKalle Valo wake_up(&il->wait_command_queue); 33367ac9a364SKalle Valo } 33377ac9a364SKalle Valo 33387ac9a364SKalle Valo /* Mark as unmapped */ 33397ac9a364SKalle Valo meta->flags = 0; 33407ac9a364SKalle Valo 33417ac9a364SKalle Valo spin_unlock_irqrestore(&il->hcmd_lock, flags); 33427ac9a364SKalle Valo } 33437ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_cmd_complete); 33447ac9a364SKalle Valo 33457ac9a364SKalle Valo MODULE_DESCRIPTION("iwl-legacy: common functions for 3945 and 4965"); 33467ac9a364SKalle Valo MODULE_VERSION(IWLWIFI_VERSION); 33477ac9a364SKalle Valo MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); 33487ac9a364SKalle Valo MODULE_LICENSE("GPL"); 33497ac9a364SKalle Valo 33507ac9a364SKalle Valo /* 33517ac9a364SKalle Valo * set bt_coex_active to true, uCode will do kill/defer 33527ac9a364SKalle Valo * every time the priority line is asserted (BT is sending signals on the 33537ac9a364SKalle Valo * priority line in the PCIx). 33547ac9a364SKalle Valo * set bt_coex_active to false, uCode will ignore the BT activity and 33557ac9a364SKalle Valo * perform the normal operation 33567ac9a364SKalle Valo * 33577ac9a364SKalle Valo * User might experience transmit issue on some platform due to WiFi/BT 33587ac9a364SKalle Valo * co-exist problem. The possible behaviors are: 33597ac9a364SKalle Valo * Able to scan and finding all the available AP 33607ac9a364SKalle Valo * Not able to associate with any AP 33617ac9a364SKalle Valo * On those platforms, WiFi communication can be restored by set 33627ac9a364SKalle Valo * "bt_coex_active" module parameter to "false" 33637ac9a364SKalle Valo * 33647ac9a364SKalle Valo * default: bt_coex_active = true (BT_COEX_ENABLE) 33657ac9a364SKalle Valo */ 33667ac9a364SKalle Valo static bool bt_coex_active = true; 33677ac9a364SKalle Valo module_param(bt_coex_active, bool, S_IRUGO); 33687ac9a364SKalle Valo MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); 33697ac9a364SKalle Valo 33707ac9a364SKalle Valo u32 il_debug_level; 33717ac9a364SKalle Valo EXPORT_SYMBOL(il_debug_level); 33727ac9a364SKalle Valo 33737ac9a364SKalle Valo const u8 il_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 33747ac9a364SKalle Valo EXPORT_SYMBOL(il_bcast_addr); 33757ac9a364SKalle Valo 33767ac9a364SKalle Valo #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ 33777ac9a364SKalle Valo #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ 33787ac9a364SKalle Valo static void 33797ac9a364SKalle Valo il_init_ht_hw_capab(const struct il_priv *il, 33807ac9a364SKalle Valo struct ieee80211_sta_ht_cap *ht_info, 33817ac9a364SKalle Valo enum ieee80211_band band) 33827ac9a364SKalle Valo { 33837ac9a364SKalle Valo u16 max_bit_rate = 0; 33847ac9a364SKalle Valo u8 rx_chains_num = il->hw_params.rx_chains_num; 33857ac9a364SKalle Valo u8 tx_chains_num = il->hw_params.tx_chains_num; 33867ac9a364SKalle Valo 33877ac9a364SKalle Valo ht_info->cap = 0; 33887ac9a364SKalle Valo memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); 33897ac9a364SKalle Valo 33907ac9a364SKalle Valo ht_info->ht_supported = true; 33917ac9a364SKalle Valo 33927ac9a364SKalle Valo ht_info->cap |= IEEE80211_HT_CAP_SGI_20; 33937ac9a364SKalle Valo max_bit_rate = MAX_BIT_RATE_20_MHZ; 33947ac9a364SKalle Valo if (il->hw_params.ht40_channel & BIT(band)) { 33957ac9a364SKalle Valo ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 33967ac9a364SKalle Valo ht_info->cap |= IEEE80211_HT_CAP_SGI_40; 33977ac9a364SKalle Valo ht_info->mcs.rx_mask[4] = 0x01; 33987ac9a364SKalle Valo max_bit_rate = MAX_BIT_RATE_40_MHZ; 33997ac9a364SKalle Valo } 34007ac9a364SKalle Valo 34017ac9a364SKalle Valo if (il->cfg->mod_params->amsdu_size_8K) 34027ac9a364SKalle Valo ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; 34037ac9a364SKalle Valo 34047ac9a364SKalle Valo ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; 34057ac9a364SKalle Valo ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; 34067ac9a364SKalle Valo 34077ac9a364SKalle Valo ht_info->mcs.rx_mask[0] = 0xFF; 34087ac9a364SKalle Valo if (rx_chains_num >= 2) 34097ac9a364SKalle Valo ht_info->mcs.rx_mask[1] = 0xFF; 34107ac9a364SKalle Valo if (rx_chains_num >= 3) 34117ac9a364SKalle Valo ht_info->mcs.rx_mask[2] = 0xFF; 34127ac9a364SKalle Valo 34137ac9a364SKalle Valo /* Highest supported Rx data rate */ 34147ac9a364SKalle Valo max_bit_rate *= rx_chains_num; 34157ac9a364SKalle Valo WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); 34167ac9a364SKalle Valo ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); 34177ac9a364SKalle Valo 34187ac9a364SKalle Valo /* Tx MCS capabilities */ 34197ac9a364SKalle Valo ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 34207ac9a364SKalle Valo if (tx_chains_num != rx_chains_num) { 34217ac9a364SKalle Valo ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; 34227ac9a364SKalle Valo ht_info->mcs.tx_params |= 34237ac9a364SKalle Valo ((tx_chains_num - 34247ac9a364SKalle Valo 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); 34257ac9a364SKalle Valo } 34267ac9a364SKalle Valo } 34277ac9a364SKalle Valo 34287ac9a364SKalle Valo /** 34297ac9a364SKalle Valo * il_init_geos - Initialize mac80211's geo/channel info based from eeprom 34307ac9a364SKalle Valo */ 34317ac9a364SKalle Valo int 34327ac9a364SKalle Valo il_init_geos(struct il_priv *il) 34337ac9a364SKalle Valo { 34347ac9a364SKalle Valo struct il_channel_info *ch; 34357ac9a364SKalle Valo struct ieee80211_supported_band *sband; 34367ac9a364SKalle Valo struct ieee80211_channel *channels; 34377ac9a364SKalle Valo struct ieee80211_channel *geo_ch; 34387ac9a364SKalle Valo struct ieee80211_rate *rates; 34397ac9a364SKalle Valo int i = 0; 34407ac9a364SKalle Valo s8 max_tx_power = 0; 34417ac9a364SKalle Valo 34427ac9a364SKalle Valo if (il->bands[IEEE80211_BAND_2GHZ].n_bitrates || 34437ac9a364SKalle Valo il->bands[IEEE80211_BAND_5GHZ].n_bitrates) { 34447ac9a364SKalle Valo D_INFO("Geography modes already initialized.\n"); 34457ac9a364SKalle Valo set_bit(S_GEO_CONFIGURED, &il->status); 34467ac9a364SKalle Valo return 0; 34477ac9a364SKalle Valo } 34487ac9a364SKalle Valo 34497ac9a364SKalle Valo channels = 34507ac9a364SKalle Valo kzalloc(sizeof(struct ieee80211_channel) * il->channel_count, 34517ac9a364SKalle Valo GFP_KERNEL); 34527ac9a364SKalle Valo if (!channels) 34537ac9a364SKalle Valo return -ENOMEM; 34547ac9a364SKalle Valo 34557ac9a364SKalle Valo rates = 34567ac9a364SKalle Valo kzalloc((sizeof(struct ieee80211_rate) * RATE_COUNT_LEGACY), 34577ac9a364SKalle Valo GFP_KERNEL); 34587ac9a364SKalle Valo if (!rates) { 34597ac9a364SKalle Valo kfree(channels); 34607ac9a364SKalle Valo return -ENOMEM; 34617ac9a364SKalle Valo } 34627ac9a364SKalle Valo 34637ac9a364SKalle Valo /* 5.2GHz channels start after the 2.4GHz channels */ 34647ac9a364SKalle Valo sband = &il->bands[IEEE80211_BAND_5GHZ]; 34657ac9a364SKalle Valo sband->channels = &channels[ARRAY_SIZE(il_eeprom_band_1)]; 34667ac9a364SKalle Valo /* just OFDM */ 34677ac9a364SKalle Valo sband->bitrates = &rates[IL_FIRST_OFDM_RATE]; 34687ac9a364SKalle Valo sband->n_bitrates = RATE_COUNT_LEGACY - IL_FIRST_OFDM_RATE; 34697ac9a364SKalle Valo 34707ac9a364SKalle Valo if (il->cfg->sku & IL_SKU_N) 34717ac9a364SKalle Valo il_init_ht_hw_capab(il, &sband->ht_cap, IEEE80211_BAND_5GHZ); 34727ac9a364SKalle Valo 34737ac9a364SKalle Valo sband = &il->bands[IEEE80211_BAND_2GHZ]; 34747ac9a364SKalle Valo sband->channels = channels; 34757ac9a364SKalle Valo /* OFDM & CCK */ 34767ac9a364SKalle Valo sband->bitrates = rates; 34777ac9a364SKalle Valo sband->n_bitrates = RATE_COUNT_LEGACY; 34787ac9a364SKalle Valo 34797ac9a364SKalle Valo if (il->cfg->sku & IL_SKU_N) 34807ac9a364SKalle Valo il_init_ht_hw_capab(il, &sband->ht_cap, IEEE80211_BAND_2GHZ); 34817ac9a364SKalle Valo 34827ac9a364SKalle Valo il->ieee_channels = channels; 34837ac9a364SKalle Valo il->ieee_rates = rates; 34847ac9a364SKalle Valo 34857ac9a364SKalle Valo for (i = 0; i < il->channel_count; i++) { 34867ac9a364SKalle Valo ch = &il->channel_info[i]; 34877ac9a364SKalle Valo 34887ac9a364SKalle Valo if (!il_is_channel_valid(ch)) 34897ac9a364SKalle Valo continue; 34907ac9a364SKalle Valo 34917ac9a364SKalle Valo sband = &il->bands[ch->band]; 34927ac9a364SKalle Valo 34937ac9a364SKalle Valo geo_ch = &sband->channels[sband->n_channels++]; 34947ac9a364SKalle Valo 34957ac9a364SKalle Valo geo_ch->center_freq = 34967ac9a364SKalle Valo ieee80211_channel_to_frequency(ch->channel, ch->band); 34977ac9a364SKalle Valo geo_ch->max_power = ch->max_power_avg; 34987ac9a364SKalle Valo geo_ch->max_antenna_gain = 0xff; 34997ac9a364SKalle Valo geo_ch->hw_value = ch->channel; 35007ac9a364SKalle Valo 35017ac9a364SKalle Valo if (il_is_channel_valid(ch)) { 35027ac9a364SKalle Valo if (!(ch->flags & EEPROM_CHANNEL_IBSS)) 35037ac9a364SKalle Valo geo_ch->flags |= IEEE80211_CHAN_NO_IR; 35047ac9a364SKalle Valo 35057ac9a364SKalle Valo if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) 35067ac9a364SKalle Valo geo_ch->flags |= IEEE80211_CHAN_NO_IR; 35077ac9a364SKalle Valo 35087ac9a364SKalle Valo if (ch->flags & EEPROM_CHANNEL_RADAR) 35097ac9a364SKalle Valo geo_ch->flags |= IEEE80211_CHAN_RADAR; 35107ac9a364SKalle Valo 35117ac9a364SKalle Valo geo_ch->flags |= ch->ht40_extension_channel; 35127ac9a364SKalle Valo 35137ac9a364SKalle Valo if (ch->max_power_avg > max_tx_power) 35147ac9a364SKalle Valo max_tx_power = ch->max_power_avg; 35157ac9a364SKalle Valo } else { 35167ac9a364SKalle Valo geo_ch->flags |= IEEE80211_CHAN_DISABLED; 35177ac9a364SKalle Valo } 35187ac9a364SKalle Valo 35197ac9a364SKalle Valo D_INFO("Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", ch->channel, 35207ac9a364SKalle Valo geo_ch->center_freq, 35217ac9a364SKalle Valo il_is_channel_a_band(ch) ? "5.2" : "2.4", 35227ac9a364SKalle Valo geo_ch-> 35237ac9a364SKalle Valo flags & IEEE80211_CHAN_DISABLED ? "restricted" : "valid", 35247ac9a364SKalle Valo geo_ch->flags); 35257ac9a364SKalle Valo } 35267ac9a364SKalle Valo 35277ac9a364SKalle Valo il->tx_power_device_lmt = max_tx_power; 35287ac9a364SKalle Valo il->tx_power_user_lmt = max_tx_power; 35297ac9a364SKalle Valo il->tx_power_next = max_tx_power; 35307ac9a364SKalle Valo 35317ac9a364SKalle Valo if (il->bands[IEEE80211_BAND_5GHZ].n_channels == 0 && 35327ac9a364SKalle Valo (il->cfg->sku & IL_SKU_A)) { 35337ac9a364SKalle Valo IL_INFO("Incorrectly detected BG card as ABG. " 35347ac9a364SKalle Valo "Please send your PCI ID 0x%04X:0x%04X to maintainer.\n", 35357ac9a364SKalle Valo il->pci_dev->device, il->pci_dev->subsystem_device); 35367ac9a364SKalle Valo il->cfg->sku &= ~IL_SKU_A; 35377ac9a364SKalle Valo } 35387ac9a364SKalle Valo 35397ac9a364SKalle Valo IL_INFO("Tunable channels: %d 802.11bg, %d 802.11a channels\n", 35407ac9a364SKalle Valo il->bands[IEEE80211_BAND_2GHZ].n_channels, 35417ac9a364SKalle Valo il->bands[IEEE80211_BAND_5GHZ].n_channels); 35427ac9a364SKalle Valo 35437ac9a364SKalle Valo set_bit(S_GEO_CONFIGURED, &il->status); 35447ac9a364SKalle Valo 35457ac9a364SKalle Valo return 0; 35467ac9a364SKalle Valo } 35477ac9a364SKalle Valo EXPORT_SYMBOL(il_init_geos); 35487ac9a364SKalle Valo 35497ac9a364SKalle Valo /* 35507ac9a364SKalle Valo * il_free_geos - undo allocations in il_init_geos 35517ac9a364SKalle Valo */ 35527ac9a364SKalle Valo void 35537ac9a364SKalle Valo il_free_geos(struct il_priv *il) 35547ac9a364SKalle Valo { 35557ac9a364SKalle Valo kfree(il->ieee_channels); 35567ac9a364SKalle Valo kfree(il->ieee_rates); 35577ac9a364SKalle Valo clear_bit(S_GEO_CONFIGURED, &il->status); 35587ac9a364SKalle Valo } 35597ac9a364SKalle Valo EXPORT_SYMBOL(il_free_geos); 35607ac9a364SKalle Valo 35617ac9a364SKalle Valo static bool 35627ac9a364SKalle Valo il_is_channel_extension(struct il_priv *il, enum ieee80211_band band, 35637ac9a364SKalle Valo u16 channel, u8 extension_chan_offset) 35647ac9a364SKalle Valo { 35657ac9a364SKalle Valo const struct il_channel_info *ch_info; 35667ac9a364SKalle Valo 35677ac9a364SKalle Valo ch_info = il_get_channel_info(il, band, channel); 35687ac9a364SKalle Valo if (!il_is_channel_valid(ch_info)) 35697ac9a364SKalle Valo return false; 35707ac9a364SKalle Valo 35717ac9a364SKalle Valo if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) 35727ac9a364SKalle Valo return !(ch_info-> 35737ac9a364SKalle Valo ht40_extension_channel & IEEE80211_CHAN_NO_HT40PLUS); 35747ac9a364SKalle Valo else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) 35757ac9a364SKalle Valo return !(ch_info-> 35767ac9a364SKalle Valo ht40_extension_channel & IEEE80211_CHAN_NO_HT40MINUS); 35777ac9a364SKalle Valo 35787ac9a364SKalle Valo return false; 35797ac9a364SKalle Valo } 35807ac9a364SKalle Valo 35817ac9a364SKalle Valo bool 35827ac9a364SKalle Valo il_is_ht40_tx_allowed(struct il_priv *il, struct ieee80211_sta_ht_cap *ht_cap) 35837ac9a364SKalle Valo { 35847ac9a364SKalle Valo if (!il->ht.enabled || !il->ht.is_40mhz) 35857ac9a364SKalle Valo return false; 35867ac9a364SKalle Valo 35877ac9a364SKalle Valo /* 35887ac9a364SKalle Valo * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 35897ac9a364SKalle Valo * the bit will not set if it is pure 40MHz case 35907ac9a364SKalle Valo */ 35917ac9a364SKalle Valo if (ht_cap && !ht_cap->ht_supported) 35927ac9a364SKalle Valo return false; 35937ac9a364SKalle Valo 35947ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUGFS 35957ac9a364SKalle Valo if (il->disable_ht40) 35967ac9a364SKalle Valo return false; 35977ac9a364SKalle Valo #endif 35987ac9a364SKalle Valo 35997ac9a364SKalle Valo return il_is_channel_extension(il, il->band, 36007ac9a364SKalle Valo le16_to_cpu(il->staging.channel), 36017ac9a364SKalle Valo il->ht.extension_chan_offset); 36027ac9a364SKalle Valo } 36037ac9a364SKalle Valo EXPORT_SYMBOL(il_is_ht40_tx_allowed); 36047ac9a364SKalle Valo 36057ac9a364SKalle Valo static u16 36067ac9a364SKalle Valo il_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) 36077ac9a364SKalle Valo { 36087ac9a364SKalle Valo u16 new_val; 36097ac9a364SKalle Valo u16 beacon_factor; 36107ac9a364SKalle Valo 36117ac9a364SKalle Valo /* 36127ac9a364SKalle Valo * If mac80211 hasn't given us a beacon interval, program 36137ac9a364SKalle Valo * the default into the device. 36147ac9a364SKalle Valo */ 36157ac9a364SKalle Valo if (!beacon_val) 36167ac9a364SKalle Valo return DEFAULT_BEACON_INTERVAL; 36177ac9a364SKalle Valo 36187ac9a364SKalle Valo /* 36197ac9a364SKalle Valo * If the beacon interval we obtained from the peer 36207ac9a364SKalle Valo * is too large, we'll have to wake up more often 36217ac9a364SKalle Valo * (and in IBSS case, we'll beacon too much) 36227ac9a364SKalle Valo * 36237ac9a364SKalle Valo * For example, if max_beacon_val is 4096, and the 36247ac9a364SKalle Valo * requested beacon interval is 7000, we'll have to 36257ac9a364SKalle Valo * use 3500 to be able to wake up on the beacons. 36267ac9a364SKalle Valo * 36277ac9a364SKalle Valo * This could badly influence beacon detection stats. 36287ac9a364SKalle Valo */ 36297ac9a364SKalle Valo 36307ac9a364SKalle Valo beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; 36317ac9a364SKalle Valo new_val = beacon_val / beacon_factor; 36327ac9a364SKalle Valo 36337ac9a364SKalle Valo if (!new_val) 36347ac9a364SKalle Valo new_val = max_beacon_val; 36357ac9a364SKalle Valo 36367ac9a364SKalle Valo return new_val; 36377ac9a364SKalle Valo } 36387ac9a364SKalle Valo 36397ac9a364SKalle Valo int 36407ac9a364SKalle Valo il_send_rxon_timing(struct il_priv *il) 36417ac9a364SKalle Valo { 36427ac9a364SKalle Valo u64 tsf; 36437ac9a364SKalle Valo s32 interval_tm, rem; 36447ac9a364SKalle Valo struct ieee80211_conf *conf = NULL; 36457ac9a364SKalle Valo u16 beacon_int; 36467ac9a364SKalle Valo struct ieee80211_vif *vif = il->vif; 36477ac9a364SKalle Valo 36487ac9a364SKalle Valo conf = &il->hw->conf; 36497ac9a364SKalle Valo 36507ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 36517ac9a364SKalle Valo 36527ac9a364SKalle Valo memset(&il->timing, 0, sizeof(struct il_rxon_time_cmd)); 36537ac9a364SKalle Valo 36547ac9a364SKalle Valo il->timing.timestamp = cpu_to_le64(il->timestamp); 36557ac9a364SKalle Valo il->timing.listen_interval = cpu_to_le16(conf->listen_interval); 36567ac9a364SKalle Valo 36577ac9a364SKalle Valo beacon_int = vif ? vif->bss_conf.beacon_int : 0; 36587ac9a364SKalle Valo 36597ac9a364SKalle Valo /* 36607ac9a364SKalle Valo * TODO: For IBSS we need to get atim_win from mac80211, 36617ac9a364SKalle Valo * for now just always use 0 36627ac9a364SKalle Valo */ 36637ac9a364SKalle Valo il->timing.atim_win = 0; 36647ac9a364SKalle Valo 36657ac9a364SKalle Valo beacon_int = 36667ac9a364SKalle Valo il_adjust_beacon_interval(beacon_int, 36677ac9a364SKalle Valo il->hw_params.max_beacon_itrvl * 36687ac9a364SKalle Valo TIME_UNIT); 36697ac9a364SKalle Valo il->timing.beacon_interval = cpu_to_le16(beacon_int); 36707ac9a364SKalle Valo 36717ac9a364SKalle Valo tsf = il->timestamp; /* tsf is modifed by do_div: copy it */ 36727ac9a364SKalle Valo interval_tm = beacon_int * TIME_UNIT; 36737ac9a364SKalle Valo rem = do_div(tsf, interval_tm); 36747ac9a364SKalle Valo il->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); 36757ac9a364SKalle Valo 36767ac9a364SKalle Valo il->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ? : 1) : 1; 36777ac9a364SKalle Valo 36787ac9a364SKalle Valo D_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", 36797ac9a364SKalle Valo le16_to_cpu(il->timing.beacon_interval), 36807ac9a364SKalle Valo le32_to_cpu(il->timing.beacon_init_val), 36817ac9a364SKalle Valo le16_to_cpu(il->timing.atim_win)); 36827ac9a364SKalle Valo 36837ac9a364SKalle Valo return il_send_cmd_pdu(il, C_RXON_TIMING, sizeof(il->timing), 36847ac9a364SKalle Valo &il->timing); 36857ac9a364SKalle Valo } 36867ac9a364SKalle Valo EXPORT_SYMBOL(il_send_rxon_timing); 36877ac9a364SKalle Valo 36887ac9a364SKalle Valo void 36897ac9a364SKalle Valo il_set_rxon_hwcrypto(struct il_priv *il, int hw_decrypt) 36907ac9a364SKalle Valo { 36917ac9a364SKalle Valo struct il_rxon_cmd *rxon = &il->staging; 36927ac9a364SKalle Valo 36937ac9a364SKalle Valo if (hw_decrypt) 36947ac9a364SKalle Valo rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; 36957ac9a364SKalle Valo else 36967ac9a364SKalle Valo rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; 36977ac9a364SKalle Valo 36987ac9a364SKalle Valo } 36997ac9a364SKalle Valo EXPORT_SYMBOL(il_set_rxon_hwcrypto); 37007ac9a364SKalle Valo 37017ac9a364SKalle Valo /* validate RXON structure is valid */ 37027ac9a364SKalle Valo int 37037ac9a364SKalle Valo il_check_rxon_cmd(struct il_priv *il) 37047ac9a364SKalle Valo { 37057ac9a364SKalle Valo struct il_rxon_cmd *rxon = &il->staging; 37067ac9a364SKalle Valo bool error = false; 37077ac9a364SKalle Valo 37087ac9a364SKalle Valo if (rxon->flags & RXON_FLG_BAND_24G_MSK) { 37097ac9a364SKalle Valo if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { 37107ac9a364SKalle Valo IL_WARN("check 2.4G: wrong narrow\n"); 37117ac9a364SKalle Valo error = true; 37127ac9a364SKalle Valo } 37137ac9a364SKalle Valo if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { 37147ac9a364SKalle Valo IL_WARN("check 2.4G: wrong radar\n"); 37157ac9a364SKalle Valo error = true; 37167ac9a364SKalle Valo } 37177ac9a364SKalle Valo } else { 37187ac9a364SKalle Valo if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { 37197ac9a364SKalle Valo IL_WARN("check 5.2G: not short slot!\n"); 37207ac9a364SKalle Valo error = true; 37217ac9a364SKalle Valo } 37227ac9a364SKalle Valo if (rxon->flags & RXON_FLG_CCK_MSK) { 37237ac9a364SKalle Valo IL_WARN("check 5.2G: CCK!\n"); 37247ac9a364SKalle Valo error = true; 37257ac9a364SKalle Valo } 37267ac9a364SKalle Valo } 37277ac9a364SKalle Valo if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { 37287ac9a364SKalle Valo IL_WARN("mac/bssid mcast!\n"); 37297ac9a364SKalle Valo error = true; 37307ac9a364SKalle Valo } 37317ac9a364SKalle Valo 37327ac9a364SKalle Valo /* make sure basic rates 6Mbps and 1Mbps are supported */ 37337ac9a364SKalle Valo if ((rxon->ofdm_basic_rates & RATE_6M_MASK) == 0 && 37347ac9a364SKalle Valo (rxon->cck_basic_rates & RATE_1M_MASK) == 0) { 37357ac9a364SKalle Valo IL_WARN("neither 1 nor 6 are basic\n"); 37367ac9a364SKalle Valo error = true; 37377ac9a364SKalle Valo } 37387ac9a364SKalle Valo 37397ac9a364SKalle Valo if (le16_to_cpu(rxon->assoc_id) > 2007) { 37407ac9a364SKalle Valo IL_WARN("aid > 2007\n"); 37417ac9a364SKalle Valo error = true; 37427ac9a364SKalle Valo } 37437ac9a364SKalle Valo 37447ac9a364SKalle Valo if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) == 37457ac9a364SKalle Valo (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { 37467ac9a364SKalle Valo IL_WARN("CCK and short slot\n"); 37477ac9a364SKalle Valo error = true; 37487ac9a364SKalle Valo } 37497ac9a364SKalle Valo 37507ac9a364SKalle Valo if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) == 37517ac9a364SKalle Valo (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { 37527ac9a364SKalle Valo IL_WARN("CCK and auto detect"); 37537ac9a364SKalle Valo error = true; 37547ac9a364SKalle Valo } 37557ac9a364SKalle Valo 37567ac9a364SKalle Valo if ((rxon-> 37577ac9a364SKalle Valo flags & (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) == 37587ac9a364SKalle Valo RXON_FLG_TGG_PROTECT_MSK) { 37597ac9a364SKalle Valo IL_WARN("TGg but no auto-detect\n"); 37607ac9a364SKalle Valo error = true; 37617ac9a364SKalle Valo } 37627ac9a364SKalle Valo 37637ac9a364SKalle Valo if (error) 37647ac9a364SKalle Valo IL_WARN("Tuning to channel %d\n", le16_to_cpu(rxon->channel)); 37657ac9a364SKalle Valo 37667ac9a364SKalle Valo if (error) { 37677ac9a364SKalle Valo IL_ERR("Invalid RXON\n"); 37687ac9a364SKalle Valo return -EINVAL; 37697ac9a364SKalle Valo } 37707ac9a364SKalle Valo return 0; 37717ac9a364SKalle Valo } 37727ac9a364SKalle Valo EXPORT_SYMBOL(il_check_rxon_cmd); 37737ac9a364SKalle Valo 37747ac9a364SKalle Valo /** 37757ac9a364SKalle Valo * il_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed 37767ac9a364SKalle Valo * @il: staging_rxon is compared to active_rxon 37777ac9a364SKalle Valo * 37787ac9a364SKalle Valo * If the RXON structure is changing enough to require a new tune, 37797ac9a364SKalle Valo * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that 37807ac9a364SKalle Valo * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. 37817ac9a364SKalle Valo */ 37827ac9a364SKalle Valo int 37837ac9a364SKalle Valo il_full_rxon_required(struct il_priv *il) 37847ac9a364SKalle Valo { 37857ac9a364SKalle Valo const struct il_rxon_cmd *staging = &il->staging; 37867ac9a364SKalle Valo const struct il_rxon_cmd *active = &il->active; 37877ac9a364SKalle Valo 37887ac9a364SKalle Valo #define CHK(cond) \ 37897ac9a364SKalle Valo if ((cond)) { \ 37907ac9a364SKalle Valo D_INFO("need full RXON - " #cond "\n"); \ 37917ac9a364SKalle Valo return 1; \ 37927ac9a364SKalle Valo } 37937ac9a364SKalle Valo 37947ac9a364SKalle Valo #define CHK_NEQ(c1, c2) \ 37957ac9a364SKalle Valo if ((c1) != (c2)) { \ 37967ac9a364SKalle Valo D_INFO("need full RXON - " \ 37977ac9a364SKalle Valo #c1 " != " #c2 " - %d != %d\n", \ 37987ac9a364SKalle Valo (c1), (c2)); \ 37997ac9a364SKalle Valo return 1; \ 38007ac9a364SKalle Valo } 38017ac9a364SKalle Valo 38027ac9a364SKalle Valo /* These items are only settable from the full RXON command */ 38037ac9a364SKalle Valo CHK(!il_is_associated(il)); 38047ac9a364SKalle Valo CHK(!ether_addr_equal_64bits(staging->bssid_addr, active->bssid_addr)); 38057ac9a364SKalle Valo CHK(!ether_addr_equal_64bits(staging->node_addr, active->node_addr)); 38067ac9a364SKalle Valo CHK(!ether_addr_equal_64bits(staging->wlap_bssid_addr, 38077ac9a364SKalle Valo active->wlap_bssid_addr)); 38087ac9a364SKalle Valo CHK_NEQ(staging->dev_type, active->dev_type); 38097ac9a364SKalle Valo CHK_NEQ(staging->channel, active->channel); 38107ac9a364SKalle Valo CHK_NEQ(staging->air_propagation, active->air_propagation); 38117ac9a364SKalle Valo CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates, 38127ac9a364SKalle Valo active->ofdm_ht_single_stream_basic_rates); 38137ac9a364SKalle Valo CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates, 38147ac9a364SKalle Valo active->ofdm_ht_dual_stream_basic_rates); 38157ac9a364SKalle Valo CHK_NEQ(staging->assoc_id, active->assoc_id); 38167ac9a364SKalle Valo 38177ac9a364SKalle Valo /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can 38187ac9a364SKalle Valo * be updated with the RXON_ASSOC command -- however only some 38197ac9a364SKalle Valo * flag transitions are allowed using RXON_ASSOC */ 38207ac9a364SKalle Valo 38217ac9a364SKalle Valo /* Check if we are not switching bands */ 38227ac9a364SKalle Valo CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK, 38237ac9a364SKalle Valo active->flags & RXON_FLG_BAND_24G_MSK); 38247ac9a364SKalle Valo 38257ac9a364SKalle Valo /* Check if we are switching association toggle */ 38267ac9a364SKalle Valo CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK, 38277ac9a364SKalle Valo active->filter_flags & RXON_FILTER_ASSOC_MSK); 38287ac9a364SKalle Valo 38297ac9a364SKalle Valo #undef CHK 38307ac9a364SKalle Valo #undef CHK_NEQ 38317ac9a364SKalle Valo 38327ac9a364SKalle Valo return 0; 38337ac9a364SKalle Valo } 38347ac9a364SKalle Valo EXPORT_SYMBOL(il_full_rxon_required); 38357ac9a364SKalle Valo 38367ac9a364SKalle Valo u8 38377ac9a364SKalle Valo il_get_lowest_plcp(struct il_priv *il) 38387ac9a364SKalle Valo { 38397ac9a364SKalle Valo /* 38407ac9a364SKalle Valo * Assign the lowest rate -- should really get this from 38417ac9a364SKalle Valo * the beacon skb from mac80211. 38427ac9a364SKalle Valo */ 38437ac9a364SKalle Valo if (il->staging.flags & RXON_FLG_BAND_24G_MSK) 38447ac9a364SKalle Valo return RATE_1M_PLCP; 38457ac9a364SKalle Valo else 38467ac9a364SKalle Valo return RATE_6M_PLCP; 38477ac9a364SKalle Valo } 38487ac9a364SKalle Valo EXPORT_SYMBOL(il_get_lowest_plcp); 38497ac9a364SKalle Valo 38507ac9a364SKalle Valo static void 38517ac9a364SKalle Valo _il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf) 38527ac9a364SKalle Valo { 38537ac9a364SKalle Valo struct il_rxon_cmd *rxon = &il->staging; 38547ac9a364SKalle Valo 38557ac9a364SKalle Valo if (!il->ht.enabled) { 38567ac9a364SKalle Valo rxon->flags &= 38577ac9a364SKalle Valo ~(RXON_FLG_CHANNEL_MODE_MSK | 38587ac9a364SKalle Valo RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | RXON_FLG_HT40_PROT_MSK 38597ac9a364SKalle Valo | RXON_FLG_HT_PROT_MSK); 38607ac9a364SKalle Valo return; 38617ac9a364SKalle Valo } 38627ac9a364SKalle Valo 38637ac9a364SKalle Valo rxon->flags |= 38647ac9a364SKalle Valo cpu_to_le32(il->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS); 38657ac9a364SKalle Valo 38667ac9a364SKalle Valo /* Set up channel bandwidth: 38677ac9a364SKalle Valo * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ 38687ac9a364SKalle Valo /* clear the HT channel mode before set the mode */ 38697ac9a364SKalle Valo rxon->flags &= 38707ac9a364SKalle Valo ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); 38717ac9a364SKalle Valo if (il_is_ht40_tx_allowed(il, NULL)) { 38727ac9a364SKalle Valo /* pure ht40 */ 38737ac9a364SKalle Valo if (il->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { 38747ac9a364SKalle Valo rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; 38757ac9a364SKalle Valo /* Note: control channel is opposite of extension channel */ 38767ac9a364SKalle Valo switch (il->ht.extension_chan_offset) { 38777ac9a364SKalle Valo case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 38787ac9a364SKalle Valo rxon->flags &= 38797ac9a364SKalle Valo ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 38807ac9a364SKalle Valo break; 38817ac9a364SKalle Valo case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 38827ac9a364SKalle Valo rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 38837ac9a364SKalle Valo break; 38847ac9a364SKalle Valo } 38857ac9a364SKalle Valo } else { 38867ac9a364SKalle Valo /* Note: control channel is opposite of extension channel */ 38877ac9a364SKalle Valo switch (il->ht.extension_chan_offset) { 38887ac9a364SKalle Valo case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 38897ac9a364SKalle Valo rxon->flags &= 38907ac9a364SKalle Valo ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); 38917ac9a364SKalle Valo rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; 38927ac9a364SKalle Valo break; 38937ac9a364SKalle Valo case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 38947ac9a364SKalle Valo rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; 38957ac9a364SKalle Valo rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; 38967ac9a364SKalle Valo break; 38977ac9a364SKalle Valo case IEEE80211_HT_PARAM_CHA_SEC_NONE: 38987ac9a364SKalle Valo default: 38997ac9a364SKalle Valo /* channel location only valid if in Mixed mode */ 39007ac9a364SKalle Valo IL_ERR("invalid extension channel offset\n"); 39017ac9a364SKalle Valo break; 39027ac9a364SKalle Valo } 39037ac9a364SKalle Valo } 39047ac9a364SKalle Valo } else { 39057ac9a364SKalle Valo rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; 39067ac9a364SKalle Valo } 39077ac9a364SKalle Valo 39087ac9a364SKalle Valo if (il->ops->set_rxon_chain) 39097ac9a364SKalle Valo il->ops->set_rxon_chain(il); 39107ac9a364SKalle Valo 39117ac9a364SKalle Valo D_ASSOC("rxon flags 0x%X operation mode :0x%X " 39127ac9a364SKalle Valo "extension channel offset 0x%x\n", le32_to_cpu(rxon->flags), 39137ac9a364SKalle Valo il->ht.protection, il->ht.extension_chan_offset); 39147ac9a364SKalle Valo } 39157ac9a364SKalle Valo 39167ac9a364SKalle Valo void 39177ac9a364SKalle Valo il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf) 39187ac9a364SKalle Valo { 39197ac9a364SKalle Valo _il_set_rxon_ht(il, ht_conf); 39207ac9a364SKalle Valo } 39217ac9a364SKalle Valo EXPORT_SYMBOL(il_set_rxon_ht); 39227ac9a364SKalle Valo 39237ac9a364SKalle Valo /* Return valid, unused, channel for a passive scan to reset the RF */ 39247ac9a364SKalle Valo u8 39257ac9a364SKalle Valo il_get_single_channel_number(struct il_priv *il, enum ieee80211_band band) 39267ac9a364SKalle Valo { 39277ac9a364SKalle Valo const struct il_channel_info *ch_info; 39287ac9a364SKalle Valo int i; 39297ac9a364SKalle Valo u8 channel = 0; 39307ac9a364SKalle Valo u8 min, max; 39317ac9a364SKalle Valo 39327ac9a364SKalle Valo if (band == IEEE80211_BAND_5GHZ) { 39337ac9a364SKalle Valo min = 14; 39347ac9a364SKalle Valo max = il->channel_count; 39357ac9a364SKalle Valo } else { 39367ac9a364SKalle Valo min = 0; 39377ac9a364SKalle Valo max = 14; 39387ac9a364SKalle Valo } 39397ac9a364SKalle Valo 39407ac9a364SKalle Valo for (i = min; i < max; i++) { 39417ac9a364SKalle Valo channel = il->channel_info[i].channel; 39427ac9a364SKalle Valo if (channel == le16_to_cpu(il->staging.channel)) 39437ac9a364SKalle Valo continue; 39447ac9a364SKalle Valo 39457ac9a364SKalle Valo ch_info = il_get_channel_info(il, band, channel); 39467ac9a364SKalle Valo if (il_is_channel_valid(ch_info)) 39477ac9a364SKalle Valo break; 39487ac9a364SKalle Valo } 39497ac9a364SKalle Valo 39507ac9a364SKalle Valo return channel; 39517ac9a364SKalle Valo } 39527ac9a364SKalle Valo EXPORT_SYMBOL(il_get_single_channel_number); 39537ac9a364SKalle Valo 39547ac9a364SKalle Valo /** 39557ac9a364SKalle Valo * il_set_rxon_channel - Set the band and channel values in staging RXON 39567ac9a364SKalle Valo * @ch: requested channel as a pointer to struct ieee80211_channel 39577ac9a364SKalle Valo 39587ac9a364SKalle Valo * NOTE: Does not commit to the hardware; it sets appropriate bit fields 39597ac9a364SKalle Valo * in the staging RXON flag structure based on the ch->band 39607ac9a364SKalle Valo */ 39617ac9a364SKalle Valo int 39627ac9a364SKalle Valo il_set_rxon_channel(struct il_priv *il, struct ieee80211_channel *ch) 39637ac9a364SKalle Valo { 39647ac9a364SKalle Valo enum ieee80211_band band = ch->band; 39657ac9a364SKalle Valo u16 channel = ch->hw_value; 39667ac9a364SKalle Valo 39677ac9a364SKalle Valo if (le16_to_cpu(il->staging.channel) == channel && il->band == band) 39687ac9a364SKalle Valo return 0; 39697ac9a364SKalle Valo 39707ac9a364SKalle Valo il->staging.channel = cpu_to_le16(channel); 39717ac9a364SKalle Valo if (band == IEEE80211_BAND_5GHZ) 39727ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_BAND_24G_MSK; 39737ac9a364SKalle Valo else 39747ac9a364SKalle Valo il->staging.flags |= RXON_FLG_BAND_24G_MSK; 39757ac9a364SKalle Valo 39767ac9a364SKalle Valo il->band = band; 39777ac9a364SKalle Valo 39787ac9a364SKalle Valo D_INFO("Staging channel set to %d [%d]\n", channel, band); 39797ac9a364SKalle Valo 39807ac9a364SKalle Valo return 0; 39817ac9a364SKalle Valo } 39827ac9a364SKalle Valo EXPORT_SYMBOL(il_set_rxon_channel); 39837ac9a364SKalle Valo 39847ac9a364SKalle Valo void 39857ac9a364SKalle Valo il_set_flags_for_band(struct il_priv *il, enum ieee80211_band band, 39867ac9a364SKalle Valo struct ieee80211_vif *vif) 39877ac9a364SKalle Valo { 39887ac9a364SKalle Valo if (band == IEEE80211_BAND_5GHZ) { 39897ac9a364SKalle Valo il->staging.flags &= 39907ac9a364SKalle Valo ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | 39917ac9a364SKalle Valo RXON_FLG_CCK_MSK); 39927ac9a364SKalle Valo il->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; 39937ac9a364SKalle Valo } else { 39947ac9a364SKalle Valo /* Copied from il_post_associate() */ 39957ac9a364SKalle Valo if (vif && vif->bss_conf.use_short_slot) 39967ac9a364SKalle Valo il->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; 39977ac9a364SKalle Valo else 39987ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; 39997ac9a364SKalle Valo 40007ac9a364SKalle Valo il->staging.flags |= RXON_FLG_BAND_24G_MSK; 40017ac9a364SKalle Valo il->staging.flags |= RXON_FLG_AUTO_DETECT_MSK; 40027ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_CCK_MSK; 40037ac9a364SKalle Valo } 40047ac9a364SKalle Valo } 40057ac9a364SKalle Valo EXPORT_SYMBOL(il_set_flags_for_band); 40067ac9a364SKalle Valo 40077ac9a364SKalle Valo /* 40087ac9a364SKalle Valo * initialize rxon structure with default values from eeprom 40097ac9a364SKalle Valo */ 40107ac9a364SKalle Valo void 40117ac9a364SKalle Valo il_connection_init_rx_config(struct il_priv *il) 40127ac9a364SKalle Valo { 40137ac9a364SKalle Valo const struct il_channel_info *ch_info; 40147ac9a364SKalle Valo 40157ac9a364SKalle Valo memset(&il->staging, 0, sizeof(il->staging)); 40167ac9a364SKalle Valo 40177ac9a364SKalle Valo switch (il->iw_mode) { 40187ac9a364SKalle Valo case NL80211_IFTYPE_UNSPECIFIED: 40197ac9a364SKalle Valo il->staging.dev_type = RXON_DEV_TYPE_ESS; 40207ac9a364SKalle Valo break; 40217ac9a364SKalle Valo case NL80211_IFTYPE_STATION: 40227ac9a364SKalle Valo il->staging.dev_type = RXON_DEV_TYPE_ESS; 40237ac9a364SKalle Valo il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; 40247ac9a364SKalle Valo break; 40257ac9a364SKalle Valo case NL80211_IFTYPE_ADHOC: 40267ac9a364SKalle Valo il->staging.dev_type = RXON_DEV_TYPE_IBSS; 40277ac9a364SKalle Valo il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; 40287ac9a364SKalle Valo il->staging.filter_flags = 40297ac9a364SKalle Valo RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; 40307ac9a364SKalle Valo break; 40317ac9a364SKalle Valo default: 40327ac9a364SKalle Valo IL_ERR("Unsupported interface type %d\n", il->vif->type); 40337ac9a364SKalle Valo return; 40347ac9a364SKalle Valo } 40357ac9a364SKalle Valo 40367ac9a364SKalle Valo #if 0 40377ac9a364SKalle Valo /* TODO: Figure out when short_preamble would be set and cache from 40387ac9a364SKalle Valo * that */ 40397ac9a364SKalle Valo if (!hw_to_local(il->hw)->short_preamble) 40407ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; 40417ac9a364SKalle Valo else 40427ac9a364SKalle Valo il->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; 40437ac9a364SKalle Valo #endif 40447ac9a364SKalle Valo 40457ac9a364SKalle Valo ch_info = 40467ac9a364SKalle Valo il_get_channel_info(il, il->band, le16_to_cpu(il->active.channel)); 40477ac9a364SKalle Valo 40487ac9a364SKalle Valo if (!ch_info) 40497ac9a364SKalle Valo ch_info = &il->channel_info[0]; 40507ac9a364SKalle Valo 40517ac9a364SKalle Valo il->staging.channel = cpu_to_le16(ch_info->channel); 40527ac9a364SKalle Valo il->band = ch_info->band; 40537ac9a364SKalle Valo 40547ac9a364SKalle Valo il_set_flags_for_band(il, il->band, il->vif); 40557ac9a364SKalle Valo 40567ac9a364SKalle Valo il->staging.ofdm_basic_rates = 40577ac9a364SKalle Valo (IL_OFDM_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF; 40587ac9a364SKalle Valo il->staging.cck_basic_rates = 40597ac9a364SKalle Valo (IL_CCK_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF; 40607ac9a364SKalle Valo 40617ac9a364SKalle Valo /* clear both MIX and PURE40 mode flag */ 40627ac9a364SKalle Valo il->staging.flags &= 40637ac9a364SKalle Valo ~(RXON_FLG_CHANNEL_MODE_MIXED | RXON_FLG_CHANNEL_MODE_PURE_40); 40647ac9a364SKalle Valo if (il->vif) 40657ac9a364SKalle Valo memcpy(il->staging.node_addr, il->vif->addr, ETH_ALEN); 40667ac9a364SKalle Valo 40677ac9a364SKalle Valo il->staging.ofdm_ht_single_stream_basic_rates = 0xff; 40687ac9a364SKalle Valo il->staging.ofdm_ht_dual_stream_basic_rates = 0xff; 40697ac9a364SKalle Valo } 40707ac9a364SKalle Valo EXPORT_SYMBOL(il_connection_init_rx_config); 40717ac9a364SKalle Valo 40727ac9a364SKalle Valo void 40737ac9a364SKalle Valo il_set_rate(struct il_priv *il) 40747ac9a364SKalle Valo { 40757ac9a364SKalle Valo const struct ieee80211_supported_band *hw = NULL; 40767ac9a364SKalle Valo struct ieee80211_rate *rate; 40777ac9a364SKalle Valo int i; 40787ac9a364SKalle Valo 40797ac9a364SKalle Valo hw = il_get_hw_mode(il, il->band); 40807ac9a364SKalle Valo if (!hw) { 40817ac9a364SKalle Valo IL_ERR("Failed to set rate: unable to get hw mode\n"); 40827ac9a364SKalle Valo return; 40837ac9a364SKalle Valo } 40847ac9a364SKalle Valo 40857ac9a364SKalle Valo il->active_rate = 0; 40867ac9a364SKalle Valo 40877ac9a364SKalle Valo for (i = 0; i < hw->n_bitrates; i++) { 40887ac9a364SKalle Valo rate = &(hw->bitrates[i]); 40897ac9a364SKalle Valo if (rate->hw_value < RATE_COUNT_LEGACY) 40907ac9a364SKalle Valo il->active_rate |= (1 << rate->hw_value); 40917ac9a364SKalle Valo } 40927ac9a364SKalle Valo 40937ac9a364SKalle Valo D_RATE("Set active_rate = %0x\n", il->active_rate); 40947ac9a364SKalle Valo 40957ac9a364SKalle Valo il->staging.cck_basic_rates = 40967ac9a364SKalle Valo (IL_CCK_BASIC_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF; 40977ac9a364SKalle Valo 40987ac9a364SKalle Valo il->staging.ofdm_basic_rates = 40997ac9a364SKalle Valo (IL_OFDM_BASIC_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF; 41007ac9a364SKalle Valo } 41017ac9a364SKalle Valo EXPORT_SYMBOL(il_set_rate); 41027ac9a364SKalle Valo 41037ac9a364SKalle Valo void 41047ac9a364SKalle Valo il_chswitch_done(struct il_priv *il, bool is_success) 41057ac9a364SKalle Valo { 41067ac9a364SKalle Valo if (test_bit(S_EXIT_PENDING, &il->status)) 41077ac9a364SKalle Valo return; 41087ac9a364SKalle Valo 41097ac9a364SKalle Valo if (test_and_clear_bit(S_CHANNEL_SWITCH_PENDING, &il->status)) 41107ac9a364SKalle Valo ieee80211_chswitch_done(il->vif, is_success); 41117ac9a364SKalle Valo } 41127ac9a364SKalle Valo EXPORT_SYMBOL(il_chswitch_done); 41137ac9a364SKalle Valo 41147ac9a364SKalle Valo void 41157ac9a364SKalle Valo il_hdl_csa(struct il_priv *il, struct il_rx_buf *rxb) 41167ac9a364SKalle Valo { 41177ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 41187ac9a364SKalle Valo struct il_csa_notification *csa = &(pkt->u.csa_notif); 41197ac9a364SKalle Valo struct il_rxon_cmd *rxon = (void *)&il->active; 41207ac9a364SKalle Valo 41217ac9a364SKalle Valo if (!test_bit(S_CHANNEL_SWITCH_PENDING, &il->status)) 41227ac9a364SKalle Valo return; 41237ac9a364SKalle Valo 41247ac9a364SKalle Valo if (!le32_to_cpu(csa->status) && csa->channel == il->switch_channel) { 41257ac9a364SKalle Valo rxon->channel = csa->channel; 41267ac9a364SKalle Valo il->staging.channel = csa->channel; 41277ac9a364SKalle Valo D_11H("CSA notif: channel %d\n", le16_to_cpu(csa->channel)); 41287ac9a364SKalle Valo il_chswitch_done(il, true); 41297ac9a364SKalle Valo } else { 41307ac9a364SKalle Valo IL_ERR("CSA notif (fail) : channel %d\n", 41317ac9a364SKalle Valo le16_to_cpu(csa->channel)); 41327ac9a364SKalle Valo il_chswitch_done(il, false); 41337ac9a364SKalle Valo } 41347ac9a364SKalle Valo } 41357ac9a364SKalle Valo EXPORT_SYMBOL(il_hdl_csa); 41367ac9a364SKalle Valo 41377ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 41387ac9a364SKalle Valo void 41397ac9a364SKalle Valo il_print_rx_config_cmd(struct il_priv *il) 41407ac9a364SKalle Valo { 41417ac9a364SKalle Valo struct il_rxon_cmd *rxon = &il->staging; 41427ac9a364SKalle Valo 41437ac9a364SKalle Valo D_RADIO("RX CONFIG:\n"); 41447ac9a364SKalle Valo il_print_hex_dump(il, IL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); 41457ac9a364SKalle Valo D_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); 41467ac9a364SKalle Valo D_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); 41477ac9a364SKalle Valo D_RADIO("u32 filter_flags: 0x%08x\n", le32_to_cpu(rxon->filter_flags)); 41487ac9a364SKalle Valo D_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); 41497ac9a364SKalle Valo D_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); 41507ac9a364SKalle Valo D_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); 41517ac9a364SKalle Valo D_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); 41527ac9a364SKalle Valo D_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); 41537ac9a364SKalle Valo D_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); 41547ac9a364SKalle Valo } 41557ac9a364SKalle Valo EXPORT_SYMBOL(il_print_rx_config_cmd); 41567ac9a364SKalle Valo #endif 41577ac9a364SKalle Valo /** 41587ac9a364SKalle Valo * il_irq_handle_error - called for HW or SW error interrupt from card 41597ac9a364SKalle Valo */ 41607ac9a364SKalle Valo void 41617ac9a364SKalle Valo il_irq_handle_error(struct il_priv *il) 41627ac9a364SKalle Valo { 41637ac9a364SKalle Valo /* Set the FW error flag -- cleared on il_down */ 41647ac9a364SKalle Valo set_bit(S_FW_ERROR, &il->status); 41657ac9a364SKalle Valo 41667ac9a364SKalle Valo /* Cancel currently queued command. */ 41677ac9a364SKalle Valo clear_bit(S_HCMD_ACTIVE, &il->status); 41687ac9a364SKalle Valo 41697ac9a364SKalle Valo IL_ERR("Loaded firmware version: %s\n", il->hw->wiphy->fw_version); 41707ac9a364SKalle Valo 41717ac9a364SKalle Valo il->ops->dump_nic_error_log(il); 41727ac9a364SKalle Valo if (il->ops->dump_fh) 41737ac9a364SKalle Valo il->ops->dump_fh(il, NULL, false); 41747ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 41757ac9a364SKalle Valo if (il_get_debug_level(il) & IL_DL_FW_ERRORS) 41767ac9a364SKalle Valo il_print_rx_config_cmd(il); 41777ac9a364SKalle Valo #endif 41787ac9a364SKalle Valo 41797ac9a364SKalle Valo wake_up(&il->wait_command_queue); 41807ac9a364SKalle Valo 41817ac9a364SKalle Valo /* Keep the restart process from trying to send host 41827ac9a364SKalle Valo * commands by clearing the INIT status bit */ 41837ac9a364SKalle Valo clear_bit(S_READY, &il->status); 41847ac9a364SKalle Valo 41857ac9a364SKalle Valo if (!test_bit(S_EXIT_PENDING, &il->status)) { 41867ac9a364SKalle Valo IL_DBG(IL_DL_FW_ERRORS, 41877ac9a364SKalle Valo "Restarting adapter due to uCode error.\n"); 41887ac9a364SKalle Valo 41897ac9a364SKalle Valo if (il->cfg->mod_params->restart_fw) 41907ac9a364SKalle Valo queue_work(il->workqueue, &il->restart); 41917ac9a364SKalle Valo } 41927ac9a364SKalle Valo } 41937ac9a364SKalle Valo EXPORT_SYMBOL(il_irq_handle_error); 41947ac9a364SKalle Valo 41957ac9a364SKalle Valo static int 41967ac9a364SKalle Valo _il_apm_stop_master(struct il_priv *il) 41977ac9a364SKalle Valo { 41987ac9a364SKalle Valo int ret = 0; 41997ac9a364SKalle Valo 42007ac9a364SKalle Valo /* stop device's busmaster DMA activity */ 42017ac9a364SKalle Valo _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); 42027ac9a364SKalle Valo 42037ac9a364SKalle Valo ret = 42047ac9a364SKalle Valo _il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 42057ac9a364SKalle Valo CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); 42067ac9a364SKalle Valo if (ret < 0) 42077ac9a364SKalle Valo IL_WARN("Master Disable Timed Out, 100 usec\n"); 42087ac9a364SKalle Valo 42097ac9a364SKalle Valo D_INFO("stop master\n"); 42107ac9a364SKalle Valo 42117ac9a364SKalle Valo return ret; 42127ac9a364SKalle Valo } 42137ac9a364SKalle Valo 42147ac9a364SKalle Valo void 42157ac9a364SKalle Valo _il_apm_stop(struct il_priv *il) 42167ac9a364SKalle Valo { 42177ac9a364SKalle Valo lockdep_assert_held(&il->reg_lock); 42187ac9a364SKalle Valo 42197ac9a364SKalle Valo D_INFO("Stop card, put in low power state\n"); 42207ac9a364SKalle Valo 42217ac9a364SKalle Valo /* Stop device's DMA activity */ 42227ac9a364SKalle Valo _il_apm_stop_master(il); 42237ac9a364SKalle Valo 42247ac9a364SKalle Valo /* Reset the entire device */ 42257ac9a364SKalle Valo _il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); 42267ac9a364SKalle Valo 42277ac9a364SKalle Valo udelay(10); 42287ac9a364SKalle Valo 42297ac9a364SKalle Valo /* 42307ac9a364SKalle Valo * Clear "initialization complete" bit to move adapter from 42317ac9a364SKalle Valo * D0A* (powered-up Active) --> D0U* (Uninitialized) state. 42327ac9a364SKalle Valo */ 42337ac9a364SKalle Valo _il_clear_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 42347ac9a364SKalle Valo } 42357ac9a364SKalle Valo EXPORT_SYMBOL(_il_apm_stop); 42367ac9a364SKalle Valo 42377ac9a364SKalle Valo void 42387ac9a364SKalle Valo il_apm_stop(struct il_priv *il) 42397ac9a364SKalle Valo { 42407ac9a364SKalle Valo unsigned long flags; 42417ac9a364SKalle Valo 42427ac9a364SKalle Valo spin_lock_irqsave(&il->reg_lock, flags); 42437ac9a364SKalle Valo _il_apm_stop(il); 42447ac9a364SKalle Valo spin_unlock_irqrestore(&il->reg_lock, flags); 42457ac9a364SKalle Valo } 42467ac9a364SKalle Valo EXPORT_SYMBOL(il_apm_stop); 42477ac9a364SKalle Valo 42487ac9a364SKalle Valo /* 42497ac9a364SKalle Valo * Start up NIC's basic functionality after it has been reset 42507ac9a364SKalle Valo * (e.g. after platform boot, or shutdown via il_apm_stop()) 42517ac9a364SKalle Valo * NOTE: This does not load uCode nor start the embedded processor 42527ac9a364SKalle Valo */ 42537ac9a364SKalle Valo int 42547ac9a364SKalle Valo il_apm_init(struct il_priv *il) 42557ac9a364SKalle Valo { 42567ac9a364SKalle Valo int ret = 0; 42577ac9a364SKalle Valo u16 lctl; 42587ac9a364SKalle Valo 42597ac9a364SKalle Valo D_INFO("Init card's basic functions\n"); 42607ac9a364SKalle Valo 42617ac9a364SKalle Valo /* 42627ac9a364SKalle Valo * Use "set_bit" below rather than "write", to preserve any hardware 42637ac9a364SKalle Valo * bits already set by default after reset. 42647ac9a364SKalle Valo */ 42657ac9a364SKalle Valo 42667ac9a364SKalle Valo /* Disable L0S exit timer (platform NMI Work/Around) */ 42677ac9a364SKalle Valo il_set_bit(il, CSR_GIO_CHICKEN_BITS, 42687ac9a364SKalle Valo CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); 42697ac9a364SKalle Valo 42707ac9a364SKalle Valo /* 42717ac9a364SKalle Valo * Disable L0s without affecting L1; 42727ac9a364SKalle Valo * don't wait for ICH L0s (ICH bug W/A) 42737ac9a364SKalle Valo */ 42747ac9a364SKalle Valo il_set_bit(il, CSR_GIO_CHICKEN_BITS, 42757ac9a364SKalle Valo CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); 42767ac9a364SKalle Valo 42777ac9a364SKalle Valo /* Set FH wait threshold to maximum (HW error during stress W/A) */ 42787ac9a364SKalle Valo il_set_bit(il, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); 42797ac9a364SKalle Valo 42807ac9a364SKalle Valo /* 42817ac9a364SKalle Valo * Enable HAP INTA (interrupt from management bus) to 42827ac9a364SKalle Valo * wake device's PCI Express link L1a -> L0s 42837ac9a364SKalle Valo * NOTE: This is no-op for 3945 (non-existent bit) 42847ac9a364SKalle Valo */ 42857ac9a364SKalle Valo il_set_bit(il, CSR_HW_IF_CONFIG_REG, 42867ac9a364SKalle Valo CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); 42877ac9a364SKalle Valo 42887ac9a364SKalle Valo /* 42897ac9a364SKalle Valo * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition. 42907ac9a364SKalle Valo * Check if BIOS (or OS) enabled L1-ASPM on this device. 42917ac9a364SKalle Valo * If so (likely), disable L0S, so device moves directly L0->L1; 42927ac9a364SKalle Valo * costs negligible amount of power savings. 42937ac9a364SKalle Valo * If not (unlikely), enable L0S, so there is at least some 42947ac9a364SKalle Valo * power savings, even without L1. 42957ac9a364SKalle Valo */ 42967ac9a364SKalle Valo if (il->cfg->set_l0s) { 42977ac9a364SKalle Valo pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl); 42987ac9a364SKalle Valo if (lctl & PCI_EXP_LNKCTL_ASPM_L1) { 42997ac9a364SKalle Valo /* L1-ASPM enabled; disable(!) L0S */ 43007ac9a364SKalle Valo il_set_bit(il, CSR_GIO_REG, 43017ac9a364SKalle Valo CSR_GIO_REG_VAL_L0S_ENABLED); 43027ac9a364SKalle Valo D_POWER("L1 Enabled; Disabling L0S\n"); 43037ac9a364SKalle Valo } else { 43047ac9a364SKalle Valo /* L1-ASPM disabled; enable(!) L0S */ 43057ac9a364SKalle Valo il_clear_bit(il, CSR_GIO_REG, 43067ac9a364SKalle Valo CSR_GIO_REG_VAL_L0S_ENABLED); 43077ac9a364SKalle Valo D_POWER("L1 Disabled; Enabling L0S\n"); 43087ac9a364SKalle Valo } 43097ac9a364SKalle Valo } 43107ac9a364SKalle Valo 43117ac9a364SKalle Valo /* Configure analog phase-lock-loop before activating to D0A */ 43127ac9a364SKalle Valo if (il->cfg->pll_cfg_val) 43137ac9a364SKalle Valo il_set_bit(il, CSR_ANA_PLL_CFG, 43147ac9a364SKalle Valo il->cfg->pll_cfg_val); 43157ac9a364SKalle Valo 43167ac9a364SKalle Valo /* 43177ac9a364SKalle Valo * Set "initialization complete" bit to move adapter from 43187ac9a364SKalle Valo * D0U* --> D0A* (powered-up active) state. 43197ac9a364SKalle Valo */ 43207ac9a364SKalle Valo il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 43217ac9a364SKalle Valo 43227ac9a364SKalle Valo /* 43237ac9a364SKalle Valo * Wait for clock stabilization; once stabilized, access to 43247ac9a364SKalle Valo * device-internal resources is supported, e.g. il_wr_prph() 43257ac9a364SKalle Valo * and accesses to uCode SRAM. 43267ac9a364SKalle Valo */ 43277ac9a364SKalle Valo ret = 43287ac9a364SKalle Valo _il_poll_bit(il, CSR_GP_CNTRL, 43297ac9a364SKalle Valo CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 43307ac9a364SKalle Valo CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); 43317ac9a364SKalle Valo if (ret < 0) { 43327ac9a364SKalle Valo D_INFO("Failed to init the card\n"); 43337ac9a364SKalle Valo goto out; 43347ac9a364SKalle Valo } 43357ac9a364SKalle Valo 43367ac9a364SKalle Valo /* 43377ac9a364SKalle Valo * Enable DMA and BSM (if used) clocks, wait for them to stabilize. 43387ac9a364SKalle Valo * BSM (Boostrap State Machine) is only in 3945 and 4965. 43397ac9a364SKalle Valo * 43407ac9a364SKalle Valo * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits 43417ac9a364SKalle Valo * do not disable clocks. This preserves any hardware bits already 43427ac9a364SKalle Valo * set by default in "CLK_CTRL_REG" after reset. 43437ac9a364SKalle Valo */ 43447ac9a364SKalle Valo if (il->cfg->use_bsm) 43457ac9a364SKalle Valo il_wr_prph(il, APMG_CLK_EN_REG, 43467ac9a364SKalle Valo APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); 43477ac9a364SKalle Valo else 43487ac9a364SKalle Valo il_wr_prph(il, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); 43497ac9a364SKalle Valo udelay(20); 43507ac9a364SKalle Valo 43517ac9a364SKalle Valo /* Disable L1-Active */ 43527ac9a364SKalle Valo il_set_bits_prph(il, APMG_PCIDEV_STT_REG, 43537ac9a364SKalle Valo APMG_PCIDEV_STT_VAL_L1_ACT_DIS); 43547ac9a364SKalle Valo 43557ac9a364SKalle Valo out: 43567ac9a364SKalle Valo return ret; 43577ac9a364SKalle Valo } 43587ac9a364SKalle Valo EXPORT_SYMBOL(il_apm_init); 43597ac9a364SKalle Valo 43607ac9a364SKalle Valo int 43617ac9a364SKalle Valo il_set_tx_power(struct il_priv *il, s8 tx_power, bool force) 43627ac9a364SKalle Valo { 43637ac9a364SKalle Valo int ret; 43647ac9a364SKalle Valo s8 prev_tx_power; 43657ac9a364SKalle Valo bool defer; 43667ac9a364SKalle Valo 43677ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 43687ac9a364SKalle Valo 43697ac9a364SKalle Valo if (il->tx_power_user_lmt == tx_power && !force) 43707ac9a364SKalle Valo return 0; 43717ac9a364SKalle Valo 43727ac9a364SKalle Valo if (!il->ops->send_tx_power) 43737ac9a364SKalle Valo return -EOPNOTSUPP; 43747ac9a364SKalle Valo 43757ac9a364SKalle Valo /* 0 dBm mean 1 milliwatt */ 43767ac9a364SKalle Valo if (tx_power < 0) { 43777ac9a364SKalle Valo IL_WARN("Requested user TXPOWER %d below 1 mW.\n", tx_power); 43787ac9a364SKalle Valo return -EINVAL; 43797ac9a364SKalle Valo } 43807ac9a364SKalle Valo 43817ac9a364SKalle Valo if (tx_power > il->tx_power_device_lmt) { 43827ac9a364SKalle Valo IL_WARN("Requested user TXPOWER %d above upper limit %d.\n", 43837ac9a364SKalle Valo tx_power, il->tx_power_device_lmt); 43847ac9a364SKalle Valo return -EINVAL; 43857ac9a364SKalle Valo } 43867ac9a364SKalle Valo 43877ac9a364SKalle Valo if (!il_is_ready_rf(il)) 43887ac9a364SKalle Valo return -EIO; 43897ac9a364SKalle Valo 43907ac9a364SKalle Valo /* scan complete and commit_rxon use tx_power_next value, 43917ac9a364SKalle Valo * it always need to be updated for newest request */ 43927ac9a364SKalle Valo il->tx_power_next = tx_power; 43937ac9a364SKalle Valo 43947ac9a364SKalle Valo /* do not set tx power when scanning or channel changing */ 43957ac9a364SKalle Valo defer = test_bit(S_SCANNING, &il->status) || 43967ac9a364SKalle Valo memcmp(&il->active, &il->staging, sizeof(il->staging)); 43977ac9a364SKalle Valo if (defer && !force) { 43987ac9a364SKalle Valo D_INFO("Deferring tx power set\n"); 43997ac9a364SKalle Valo return 0; 44007ac9a364SKalle Valo } 44017ac9a364SKalle Valo 44027ac9a364SKalle Valo prev_tx_power = il->tx_power_user_lmt; 44037ac9a364SKalle Valo il->tx_power_user_lmt = tx_power; 44047ac9a364SKalle Valo 44057ac9a364SKalle Valo ret = il->ops->send_tx_power(il); 44067ac9a364SKalle Valo 44077ac9a364SKalle Valo /* if fail to set tx_power, restore the orig. tx power */ 44087ac9a364SKalle Valo if (ret) { 44097ac9a364SKalle Valo il->tx_power_user_lmt = prev_tx_power; 44107ac9a364SKalle Valo il->tx_power_next = prev_tx_power; 44117ac9a364SKalle Valo } 44127ac9a364SKalle Valo return ret; 44137ac9a364SKalle Valo } 44147ac9a364SKalle Valo EXPORT_SYMBOL(il_set_tx_power); 44157ac9a364SKalle Valo 44167ac9a364SKalle Valo void 44177ac9a364SKalle Valo il_send_bt_config(struct il_priv *il) 44187ac9a364SKalle Valo { 44197ac9a364SKalle Valo struct il_bt_cmd bt_cmd = { 44207ac9a364SKalle Valo .lead_time = BT_LEAD_TIME_DEF, 44217ac9a364SKalle Valo .max_kill = BT_MAX_KILL_DEF, 44227ac9a364SKalle Valo .kill_ack_mask = 0, 44237ac9a364SKalle Valo .kill_cts_mask = 0, 44247ac9a364SKalle Valo }; 44257ac9a364SKalle Valo 44267ac9a364SKalle Valo if (!bt_coex_active) 44277ac9a364SKalle Valo bt_cmd.flags = BT_COEX_DISABLE; 44287ac9a364SKalle Valo else 44297ac9a364SKalle Valo bt_cmd.flags = BT_COEX_ENABLE; 44307ac9a364SKalle Valo 44317ac9a364SKalle Valo D_INFO("BT coex %s\n", 44327ac9a364SKalle Valo (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); 44337ac9a364SKalle Valo 44347ac9a364SKalle Valo if (il_send_cmd_pdu(il, C_BT_CONFIG, sizeof(struct il_bt_cmd), &bt_cmd)) 44357ac9a364SKalle Valo IL_ERR("failed to send BT Coex Config\n"); 44367ac9a364SKalle Valo } 44377ac9a364SKalle Valo EXPORT_SYMBOL(il_send_bt_config); 44387ac9a364SKalle Valo 44397ac9a364SKalle Valo int 44407ac9a364SKalle Valo il_send_stats_request(struct il_priv *il, u8 flags, bool clear) 44417ac9a364SKalle Valo { 44427ac9a364SKalle Valo struct il_stats_cmd stats_cmd = { 44437ac9a364SKalle Valo .configuration_flags = clear ? IL_STATS_CONF_CLEAR_STATS : 0, 44447ac9a364SKalle Valo }; 44457ac9a364SKalle Valo 44467ac9a364SKalle Valo if (flags & CMD_ASYNC) 44477ac9a364SKalle Valo return il_send_cmd_pdu_async(il, C_STATS, sizeof(struct il_stats_cmd), 44487ac9a364SKalle Valo &stats_cmd, NULL); 44497ac9a364SKalle Valo else 44507ac9a364SKalle Valo return il_send_cmd_pdu(il, C_STATS, sizeof(struct il_stats_cmd), 44517ac9a364SKalle Valo &stats_cmd); 44527ac9a364SKalle Valo } 44537ac9a364SKalle Valo EXPORT_SYMBOL(il_send_stats_request); 44547ac9a364SKalle Valo 44557ac9a364SKalle Valo void 44567ac9a364SKalle Valo il_hdl_pm_sleep(struct il_priv *il, struct il_rx_buf *rxb) 44577ac9a364SKalle Valo { 44587ac9a364SKalle Valo #ifdef CONFIG_IWLEGACY_DEBUG 44597ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 44607ac9a364SKalle Valo struct il_sleep_notification *sleep = &(pkt->u.sleep_notif); 44617ac9a364SKalle Valo D_RX("sleep mode: %d, src: %d\n", 44627ac9a364SKalle Valo sleep->pm_sleep_mode, sleep->pm_wakeup_src); 44637ac9a364SKalle Valo #endif 44647ac9a364SKalle Valo } 44657ac9a364SKalle Valo EXPORT_SYMBOL(il_hdl_pm_sleep); 44667ac9a364SKalle Valo 44677ac9a364SKalle Valo void 44687ac9a364SKalle Valo il_hdl_pm_debug_stats(struct il_priv *il, struct il_rx_buf *rxb) 44697ac9a364SKalle Valo { 44707ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 44717ac9a364SKalle Valo u32 len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; 44727ac9a364SKalle Valo D_RADIO("Dumping %d bytes of unhandled notification for %s:\n", len, 44737ac9a364SKalle Valo il_get_cmd_string(pkt->hdr.cmd)); 44747ac9a364SKalle Valo il_print_hex_dump(il, IL_DL_RADIO, pkt->u.raw, len); 44757ac9a364SKalle Valo } 44767ac9a364SKalle Valo EXPORT_SYMBOL(il_hdl_pm_debug_stats); 44777ac9a364SKalle Valo 44787ac9a364SKalle Valo void 44797ac9a364SKalle Valo il_hdl_error(struct il_priv *il, struct il_rx_buf *rxb) 44807ac9a364SKalle Valo { 44817ac9a364SKalle Valo struct il_rx_pkt *pkt = rxb_addr(rxb); 44827ac9a364SKalle Valo 44837ac9a364SKalle Valo IL_ERR("Error Reply type 0x%08X cmd %s (0x%02X) " 44847ac9a364SKalle Valo "seq 0x%04X ser 0x%08X\n", 44857ac9a364SKalle Valo le32_to_cpu(pkt->u.err_resp.error_type), 44867ac9a364SKalle Valo il_get_cmd_string(pkt->u.err_resp.cmd_id), 44877ac9a364SKalle Valo pkt->u.err_resp.cmd_id, 44887ac9a364SKalle Valo le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), 44897ac9a364SKalle Valo le32_to_cpu(pkt->u.err_resp.error_info)); 44907ac9a364SKalle Valo } 44917ac9a364SKalle Valo EXPORT_SYMBOL(il_hdl_error); 44927ac9a364SKalle Valo 44937ac9a364SKalle Valo void 44947ac9a364SKalle Valo il_clear_isr_stats(struct il_priv *il) 44957ac9a364SKalle Valo { 44967ac9a364SKalle Valo memset(&il->isr_stats, 0, sizeof(il->isr_stats)); 44977ac9a364SKalle Valo } 44987ac9a364SKalle Valo 44997ac9a364SKalle Valo int 45007ac9a364SKalle Valo il_mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, 45017ac9a364SKalle Valo const struct ieee80211_tx_queue_params *params) 45027ac9a364SKalle Valo { 45037ac9a364SKalle Valo struct il_priv *il = hw->priv; 45047ac9a364SKalle Valo unsigned long flags; 45057ac9a364SKalle Valo int q; 45067ac9a364SKalle Valo 45077ac9a364SKalle Valo D_MAC80211("enter\n"); 45087ac9a364SKalle Valo 45097ac9a364SKalle Valo if (!il_is_ready_rf(il)) { 45107ac9a364SKalle Valo D_MAC80211("leave - RF not ready\n"); 45117ac9a364SKalle Valo return -EIO; 45127ac9a364SKalle Valo } 45137ac9a364SKalle Valo 45147ac9a364SKalle Valo if (queue >= AC_NUM) { 45157ac9a364SKalle Valo D_MAC80211("leave - queue >= AC_NUM %d\n", queue); 45167ac9a364SKalle Valo return 0; 45177ac9a364SKalle Valo } 45187ac9a364SKalle Valo 45197ac9a364SKalle Valo q = AC_NUM - 1 - queue; 45207ac9a364SKalle Valo 45217ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 45227ac9a364SKalle Valo 45237ac9a364SKalle Valo il->qos_data.def_qos_parm.ac[q].cw_min = 45247ac9a364SKalle Valo cpu_to_le16(params->cw_min); 45257ac9a364SKalle Valo il->qos_data.def_qos_parm.ac[q].cw_max = 45267ac9a364SKalle Valo cpu_to_le16(params->cw_max); 45277ac9a364SKalle Valo il->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; 45287ac9a364SKalle Valo il->qos_data.def_qos_parm.ac[q].edca_txop = 45297ac9a364SKalle Valo cpu_to_le16((params->txop * 32)); 45307ac9a364SKalle Valo 45317ac9a364SKalle Valo il->qos_data.def_qos_parm.ac[q].reserved1 = 0; 45327ac9a364SKalle Valo 45337ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 45347ac9a364SKalle Valo 45357ac9a364SKalle Valo D_MAC80211("leave\n"); 45367ac9a364SKalle Valo return 0; 45377ac9a364SKalle Valo } 45387ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_conf_tx); 45397ac9a364SKalle Valo 45407ac9a364SKalle Valo int 45417ac9a364SKalle Valo il_mac_tx_last_beacon(struct ieee80211_hw *hw) 45427ac9a364SKalle Valo { 45437ac9a364SKalle Valo struct il_priv *il = hw->priv; 45447ac9a364SKalle Valo int ret; 45457ac9a364SKalle Valo 45467ac9a364SKalle Valo D_MAC80211("enter\n"); 45477ac9a364SKalle Valo 45487ac9a364SKalle Valo ret = (il->ibss_manager == IL_IBSS_MANAGER); 45497ac9a364SKalle Valo 45507ac9a364SKalle Valo D_MAC80211("leave ret %d\n", ret); 45517ac9a364SKalle Valo return ret; 45527ac9a364SKalle Valo } 45537ac9a364SKalle Valo EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon); 45547ac9a364SKalle Valo 45557ac9a364SKalle Valo static int 45567ac9a364SKalle Valo il_set_mode(struct il_priv *il) 45577ac9a364SKalle Valo { 45587ac9a364SKalle Valo il_connection_init_rx_config(il); 45597ac9a364SKalle Valo 45607ac9a364SKalle Valo if (il->ops->set_rxon_chain) 45617ac9a364SKalle Valo il->ops->set_rxon_chain(il); 45627ac9a364SKalle Valo 45637ac9a364SKalle Valo return il_commit_rxon(il); 45647ac9a364SKalle Valo } 45657ac9a364SKalle Valo 45667ac9a364SKalle Valo int 45677ac9a364SKalle Valo il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 45687ac9a364SKalle Valo { 45697ac9a364SKalle Valo struct il_priv *il = hw->priv; 45707ac9a364SKalle Valo int err; 45717ac9a364SKalle Valo bool reset; 45727ac9a364SKalle Valo 45737ac9a364SKalle Valo mutex_lock(&il->mutex); 45747ac9a364SKalle Valo D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr); 45757ac9a364SKalle Valo 45767ac9a364SKalle Valo if (!il_is_ready_rf(il)) { 45777ac9a364SKalle Valo IL_WARN("Try to add interface when device not ready\n"); 45787ac9a364SKalle Valo err = -EINVAL; 45797ac9a364SKalle Valo goto out; 45807ac9a364SKalle Valo } 45817ac9a364SKalle Valo 45827ac9a364SKalle Valo /* 45837ac9a364SKalle Valo * We do not support multiple virtual interfaces, but on hardware reset 45847ac9a364SKalle Valo * we have to add the same interface again. 45857ac9a364SKalle Valo */ 45867ac9a364SKalle Valo reset = (il->vif == vif); 45877ac9a364SKalle Valo if (il->vif && !reset) { 45887ac9a364SKalle Valo err = -EOPNOTSUPP; 45897ac9a364SKalle Valo goto out; 45907ac9a364SKalle Valo } 45917ac9a364SKalle Valo 45927ac9a364SKalle Valo il->vif = vif; 45937ac9a364SKalle Valo il->iw_mode = vif->type; 45947ac9a364SKalle Valo 45957ac9a364SKalle Valo err = il_set_mode(il); 45967ac9a364SKalle Valo if (err) { 45977ac9a364SKalle Valo IL_WARN("Fail to set mode %d\n", vif->type); 45987ac9a364SKalle Valo if (!reset) { 45997ac9a364SKalle Valo il->vif = NULL; 46007ac9a364SKalle Valo il->iw_mode = NL80211_IFTYPE_STATION; 46017ac9a364SKalle Valo } 46027ac9a364SKalle Valo } 46037ac9a364SKalle Valo 46047ac9a364SKalle Valo out: 46057ac9a364SKalle Valo D_MAC80211("leave err %d\n", err); 46067ac9a364SKalle Valo mutex_unlock(&il->mutex); 46077ac9a364SKalle Valo 46087ac9a364SKalle Valo return err; 46097ac9a364SKalle Valo } 46107ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_add_interface); 46117ac9a364SKalle Valo 46127ac9a364SKalle Valo static void 46137ac9a364SKalle Valo il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif) 46147ac9a364SKalle Valo { 46157ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 46167ac9a364SKalle Valo 46177ac9a364SKalle Valo if (il->scan_vif == vif) { 46187ac9a364SKalle Valo il_scan_cancel_timeout(il, 200); 46197ac9a364SKalle Valo il_force_scan_end(il); 46207ac9a364SKalle Valo } 46217ac9a364SKalle Valo 46227ac9a364SKalle Valo il_set_mode(il); 46237ac9a364SKalle Valo } 46247ac9a364SKalle Valo 46257ac9a364SKalle Valo void 46267ac9a364SKalle Valo il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 46277ac9a364SKalle Valo { 46287ac9a364SKalle Valo struct il_priv *il = hw->priv; 46297ac9a364SKalle Valo 46307ac9a364SKalle Valo mutex_lock(&il->mutex); 46317ac9a364SKalle Valo D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr); 46327ac9a364SKalle Valo 46337ac9a364SKalle Valo WARN_ON(il->vif != vif); 46347ac9a364SKalle Valo il->vif = NULL; 46357ac9a364SKalle Valo il->iw_mode = NL80211_IFTYPE_UNSPECIFIED; 46367ac9a364SKalle Valo il_teardown_interface(il, vif); 46377ac9a364SKalle Valo eth_zero_addr(il->bssid); 46387ac9a364SKalle Valo 46397ac9a364SKalle Valo D_MAC80211("leave\n"); 46407ac9a364SKalle Valo mutex_unlock(&il->mutex); 46417ac9a364SKalle Valo } 46427ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_remove_interface); 46437ac9a364SKalle Valo 46447ac9a364SKalle Valo int 46457ac9a364SKalle Valo il_alloc_txq_mem(struct il_priv *il) 46467ac9a364SKalle Valo { 46477ac9a364SKalle Valo if (!il->txq) 46487ac9a364SKalle Valo il->txq = 46497ac9a364SKalle Valo kzalloc(sizeof(struct il_tx_queue) * 46507ac9a364SKalle Valo il->cfg->num_of_queues, GFP_KERNEL); 46517ac9a364SKalle Valo if (!il->txq) { 46527ac9a364SKalle Valo IL_ERR("Not enough memory for txq\n"); 46537ac9a364SKalle Valo return -ENOMEM; 46547ac9a364SKalle Valo } 46557ac9a364SKalle Valo return 0; 46567ac9a364SKalle Valo } 46577ac9a364SKalle Valo EXPORT_SYMBOL(il_alloc_txq_mem); 46587ac9a364SKalle Valo 46597ac9a364SKalle Valo void 46607ac9a364SKalle Valo il_free_txq_mem(struct il_priv *il) 46617ac9a364SKalle Valo { 46627ac9a364SKalle Valo kfree(il->txq); 46637ac9a364SKalle Valo il->txq = NULL; 46647ac9a364SKalle Valo } 46657ac9a364SKalle Valo EXPORT_SYMBOL(il_free_txq_mem); 46667ac9a364SKalle Valo 46677ac9a364SKalle Valo int 46687ac9a364SKalle Valo il_force_reset(struct il_priv *il, bool external) 46697ac9a364SKalle Valo { 46707ac9a364SKalle Valo struct il_force_reset *force_reset; 46717ac9a364SKalle Valo 46727ac9a364SKalle Valo if (test_bit(S_EXIT_PENDING, &il->status)) 46737ac9a364SKalle Valo return -EINVAL; 46747ac9a364SKalle Valo 46757ac9a364SKalle Valo force_reset = &il->force_reset; 46767ac9a364SKalle Valo force_reset->reset_request_count++; 46777ac9a364SKalle Valo if (!external) { 46787ac9a364SKalle Valo if (force_reset->last_force_reset_jiffies && 46797ac9a364SKalle Valo time_after(force_reset->last_force_reset_jiffies + 46807ac9a364SKalle Valo force_reset->reset_duration, jiffies)) { 46817ac9a364SKalle Valo D_INFO("force reset rejected\n"); 46827ac9a364SKalle Valo force_reset->reset_reject_count++; 46837ac9a364SKalle Valo return -EAGAIN; 46847ac9a364SKalle Valo } 46857ac9a364SKalle Valo } 46867ac9a364SKalle Valo force_reset->reset_success_count++; 46877ac9a364SKalle Valo force_reset->last_force_reset_jiffies = jiffies; 46887ac9a364SKalle Valo 46897ac9a364SKalle Valo /* 46907ac9a364SKalle Valo * if the request is from external(ex: debugfs), 46917ac9a364SKalle Valo * then always perform the request in regardless the module 46927ac9a364SKalle Valo * parameter setting 46937ac9a364SKalle Valo * if the request is from internal (uCode error or driver 46947ac9a364SKalle Valo * detect failure), then fw_restart module parameter 46957ac9a364SKalle Valo * need to be check before performing firmware reload 46967ac9a364SKalle Valo */ 46977ac9a364SKalle Valo 46987ac9a364SKalle Valo if (!external && !il->cfg->mod_params->restart_fw) { 46997ac9a364SKalle Valo D_INFO("Cancel firmware reload based on " 47007ac9a364SKalle Valo "module parameter setting\n"); 47017ac9a364SKalle Valo return 0; 47027ac9a364SKalle Valo } 47037ac9a364SKalle Valo 47047ac9a364SKalle Valo IL_ERR("On demand firmware reload\n"); 47057ac9a364SKalle Valo 47067ac9a364SKalle Valo /* Set the FW error flag -- cleared on il_down */ 47077ac9a364SKalle Valo set_bit(S_FW_ERROR, &il->status); 47087ac9a364SKalle Valo wake_up(&il->wait_command_queue); 47097ac9a364SKalle Valo /* 47107ac9a364SKalle Valo * Keep the restart process from trying to send host 47117ac9a364SKalle Valo * commands by clearing the INIT status bit 47127ac9a364SKalle Valo */ 47137ac9a364SKalle Valo clear_bit(S_READY, &il->status); 47147ac9a364SKalle Valo queue_work(il->workqueue, &il->restart); 47157ac9a364SKalle Valo 47167ac9a364SKalle Valo return 0; 47177ac9a364SKalle Valo } 47187ac9a364SKalle Valo EXPORT_SYMBOL(il_force_reset); 47197ac9a364SKalle Valo 47207ac9a364SKalle Valo int 47217ac9a364SKalle Valo il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 47227ac9a364SKalle Valo enum nl80211_iftype newtype, bool newp2p) 47237ac9a364SKalle Valo { 47247ac9a364SKalle Valo struct il_priv *il = hw->priv; 47257ac9a364SKalle Valo int err; 47267ac9a364SKalle Valo 47277ac9a364SKalle Valo mutex_lock(&il->mutex); 47287ac9a364SKalle Valo D_MAC80211("enter: type %d, addr %pM newtype %d newp2p %d\n", 47297ac9a364SKalle Valo vif->type, vif->addr, newtype, newp2p); 47307ac9a364SKalle Valo 47317ac9a364SKalle Valo if (newp2p) { 47327ac9a364SKalle Valo err = -EOPNOTSUPP; 47337ac9a364SKalle Valo goto out; 47347ac9a364SKalle Valo } 47357ac9a364SKalle Valo 47367ac9a364SKalle Valo if (!il->vif || !il_is_ready_rf(il)) { 47377ac9a364SKalle Valo /* 47387ac9a364SKalle Valo * Huh? But wait ... this can maybe happen when 47397ac9a364SKalle Valo * we're in the middle of a firmware restart! 47407ac9a364SKalle Valo */ 47417ac9a364SKalle Valo err = -EBUSY; 47427ac9a364SKalle Valo goto out; 47437ac9a364SKalle Valo } 47447ac9a364SKalle Valo 47457ac9a364SKalle Valo /* success */ 47467ac9a364SKalle Valo vif->type = newtype; 47477ac9a364SKalle Valo vif->p2p = false; 47487ac9a364SKalle Valo il->iw_mode = newtype; 47497ac9a364SKalle Valo il_teardown_interface(il, vif); 47507ac9a364SKalle Valo err = 0; 47517ac9a364SKalle Valo 47527ac9a364SKalle Valo out: 47537ac9a364SKalle Valo D_MAC80211("leave err %d\n", err); 47547ac9a364SKalle Valo mutex_unlock(&il->mutex); 47557ac9a364SKalle Valo 47567ac9a364SKalle Valo return err; 47577ac9a364SKalle Valo } 47587ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_change_interface); 47597ac9a364SKalle Valo 47607ac9a364SKalle Valo void il_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 47617ac9a364SKalle Valo u32 queues, bool drop) 47627ac9a364SKalle Valo { 47637ac9a364SKalle Valo struct il_priv *il = hw->priv; 47647ac9a364SKalle Valo unsigned long timeout = jiffies + msecs_to_jiffies(500); 47657ac9a364SKalle Valo int i; 47667ac9a364SKalle Valo 47677ac9a364SKalle Valo mutex_lock(&il->mutex); 47687ac9a364SKalle Valo D_MAC80211("enter\n"); 47697ac9a364SKalle Valo 47707ac9a364SKalle Valo if (il->txq == NULL) 47717ac9a364SKalle Valo goto out; 47727ac9a364SKalle Valo 47737ac9a364SKalle Valo for (i = 0; i < il->hw_params.max_txq_num; i++) { 47747ac9a364SKalle Valo struct il_queue *q; 47757ac9a364SKalle Valo 47767ac9a364SKalle Valo if (i == il->cmd_queue) 47777ac9a364SKalle Valo continue; 47787ac9a364SKalle Valo 47797ac9a364SKalle Valo q = &il->txq[i].q; 47807ac9a364SKalle Valo if (q->read_ptr == q->write_ptr) 47817ac9a364SKalle Valo continue; 47827ac9a364SKalle Valo 47837ac9a364SKalle Valo if (time_after(jiffies, timeout)) { 47847ac9a364SKalle Valo IL_ERR("Failed to flush queue %d\n", q->id); 47857ac9a364SKalle Valo break; 47867ac9a364SKalle Valo } 47877ac9a364SKalle Valo 47887ac9a364SKalle Valo msleep(20); 47897ac9a364SKalle Valo } 47907ac9a364SKalle Valo out: 47917ac9a364SKalle Valo D_MAC80211("leave\n"); 47927ac9a364SKalle Valo mutex_unlock(&il->mutex); 47937ac9a364SKalle Valo } 47947ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_flush); 47957ac9a364SKalle Valo 47967ac9a364SKalle Valo /* 47977ac9a364SKalle Valo * On every watchdog tick we check (latest) time stamp. If it does not 47987ac9a364SKalle Valo * change during timeout period and queue is not empty we reset firmware. 47997ac9a364SKalle Valo */ 48007ac9a364SKalle Valo static int 48017ac9a364SKalle Valo il_check_stuck_queue(struct il_priv *il, int cnt) 48027ac9a364SKalle Valo { 48037ac9a364SKalle Valo struct il_tx_queue *txq = &il->txq[cnt]; 48047ac9a364SKalle Valo struct il_queue *q = &txq->q; 48057ac9a364SKalle Valo unsigned long timeout; 48067ac9a364SKalle Valo unsigned long now = jiffies; 48077ac9a364SKalle Valo int ret; 48087ac9a364SKalle Valo 48097ac9a364SKalle Valo if (q->read_ptr == q->write_ptr) { 48107ac9a364SKalle Valo txq->time_stamp = now; 48117ac9a364SKalle Valo return 0; 48127ac9a364SKalle Valo } 48137ac9a364SKalle Valo 48147ac9a364SKalle Valo timeout = 48157ac9a364SKalle Valo txq->time_stamp + 48167ac9a364SKalle Valo msecs_to_jiffies(il->cfg->wd_timeout); 48177ac9a364SKalle Valo 48187ac9a364SKalle Valo if (time_after(now, timeout)) { 48197ac9a364SKalle Valo IL_ERR("Queue %d stuck for %u ms.\n", q->id, 48207ac9a364SKalle Valo jiffies_to_msecs(now - txq->time_stamp)); 48217ac9a364SKalle Valo ret = il_force_reset(il, false); 48227ac9a364SKalle Valo return (ret == -EAGAIN) ? 0 : 1; 48237ac9a364SKalle Valo } 48247ac9a364SKalle Valo 48257ac9a364SKalle Valo return 0; 48267ac9a364SKalle Valo } 48277ac9a364SKalle Valo 48287ac9a364SKalle Valo /* 48297ac9a364SKalle Valo * Making watchdog tick be a quarter of timeout assure we will 48307ac9a364SKalle Valo * discover the queue hung between timeout and 1.25*timeout 48317ac9a364SKalle Valo */ 48327ac9a364SKalle Valo #define IL_WD_TICK(timeout) ((timeout) / 4) 48337ac9a364SKalle Valo 48347ac9a364SKalle Valo /* 48357ac9a364SKalle Valo * Watchdog timer callback, we check each tx queue for stuck, if if hung 48367ac9a364SKalle Valo * we reset the firmware. If everything is fine just rearm the timer. 48377ac9a364SKalle Valo */ 48387ac9a364SKalle Valo void 48397ac9a364SKalle Valo il_bg_watchdog(unsigned long data) 48407ac9a364SKalle Valo { 48417ac9a364SKalle Valo struct il_priv *il = (struct il_priv *)data; 48427ac9a364SKalle Valo int cnt; 48437ac9a364SKalle Valo unsigned long timeout; 48447ac9a364SKalle Valo 48457ac9a364SKalle Valo if (test_bit(S_EXIT_PENDING, &il->status)) 48467ac9a364SKalle Valo return; 48477ac9a364SKalle Valo 48487ac9a364SKalle Valo timeout = il->cfg->wd_timeout; 48497ac9a364SKalle Valo if (timeout == 0) 48507ac9a364SKalle Valo return; 48517ac9a364SKalle Valo 48527ac9a364SKalle Valo /* monitor and check for stuck cmd queue */ 48537ac9a364SKalle Valo if (il_check_stuck_queue(il, il->cmd_queue)) 48547ac9a364SKalle Valo return; 48557ac9a364SKalle Valo 48567ac9a364SKalle Valo /* monitor and check for other stuck queues */ 48577ac9a364SKalle Valo for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { 48587ac9a364SKalle Valo /* skip as we already checked the command queue */ 48597ac9a364SKalle Valo if (cnt == il->cmd_queue) 48607ac9a364SKalle Valo continue; 48617ac9a364SKalle Valo if (il_check_stuck_queue(il, cnt)) 48627ac9a364SKalle Valo return; 48637ac9a364SKalle Valo } 48647ac9a364SKalle Valo 48657ac9a364SKalle Valo mod_timer(&il->watchdog, 48667ac9a364SKalle Valo jiffies + msecs_to_jiffies(IL_WD_TICK(timeout))); 48677ac9a364SKalle Valo } 48687ac9a364SKalle Valo EXPORT_SYMBOL(il_bg_watchdog); 48697ac9a364SKalle Valo 48707ac9a364SKalle Valo void 48717ac9a364SKalle Valo il_setup_watchdog(struct il_priv *il) 48727ac9a364SKalle Valo { 48737ac9a364SKalle Valo unsigned int timeout = il->cfg->wd_timeout; 48747ac9a364SKalle Valo 48757ac9a364SKalle Valo if (timeout) 48767ac9a364SKalle Valo mod_timer(&il->watchdog, 48777ac9a364SKalle Valo jiffies + msecs_to_jiffies(IL_WD_TICK(timeout))); 48787ac9a364SKalle Valo else 48797ac9a364SKalle Valo del_timer(&il->watchdog); 48807ac9a364SKalle Valo } 48817ac9a364SKalle Valo EXPORT_SYMBOL(il_setup_watchdog); 48827ac9a364SKalle Valo 48837ac9a364SKalle Valo /* 48847ac9a364SKalle Valo * extended beacon time format 48857ac9a364SKalle Valo * time in usec will be changed into a 32-bit value in extended:internal format 48867ac9a364SKalle Valo * the extended part is the beacon counts 48877ac9a364SKalle Valo * the internal part is the time in usec within one beacon interval 48887ac9a364SKalle Valo */ 48897ac9a364SKalle Valo u32 48907ac9a364SKalle Valo il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval) 48917ac9a364SKalle Valo { 48927ac9a364SKalle Valo u32 quot; 48937ac9a364SKalle Valo u32 rem; 48947ac9a364SKalle Valo u32 interval = beacon_interval * TIME_UNIT; 48957ac9a364SKalle Valo 48967ac9a364SKalle Valo if (!interval || !usec) 48977ac9a364SKalle Valo return 0; 48987ac9a364SKalle Valo 48997ac9a364SKalle Valo quot = 49007ac9a364SKalle Valo (usec / 49017ac9a364SKalle Valo interval) & (il_beacon_time_mask_high(il, 49027ac9a364SKalle Valo il->hw_params. 49037ac9a364SKalle Valo beacon_time_tsf_bits) >> il-> 49047ac9a364SKalle Valo hw_params.beacon_time_tsf_bits); 49057ac9a364SKalle Valo rem = 49067ac9a364SKalle Valo (usec % interval) & il_beacon_time_mask_low(il, 49077ac9a364SKalle Valo il->hw_params. 49087ac9a364SKalle Valo beacon_time_tsf_bits); 49097ac9a364SKalle Valo 49107ac9a364SKalle Valo return (quot << il->hw_params.beacon_time_tsf_bits) + rem; 49117ac9a364SKalle Valo } 49127ac9a364SKalle Valo EXPORT_SYMBOL(il_usecs_to_beacons); 49137ac9a364SKalle Valo 49147ac9a364SKalle Valo /* base is usually what we get from ucode with each received frame, 49157ac9a364SKalle Valo * the same as HW timer counter counting down 49167ac9a364SKalle Valo */ 49177ac9a364SKalle Valo __le32 49187ac9a364SKalle Valo il_add_beacon_time(struct il_priv *il, u32 base, u32 addon, 49197ac9a364SKalle Valo u32 beacon_interval) 49207ac9a364SKalle Valo { 49217ac9a364SKalle Valo u32 base_low = base & il_beacon_time_mask_low(il, 49227ac9a364SKalle Valo il->hw_params. 49237ac9a364SKalle Valo beacon_time_tsf_bits); 49247ac9a364SKalle Valo u32 addon_low = addon & il_beacon_time_mask_low(il, 49257ac9a364SKalle Valo il->hw_params. 49267ac9a364SKalle Valo beacon_time_tsf_bits); 49277ac9a364SKalle Valo u32 interval = beacon_interval * TIME_UNIT; 49287ac9a364SKalle Valo u32 res = (base & il_beacon_time_mask_high(il, 49297ac9a364SKalle Valo il->hw_params. 49307ac9a364SKalle Valo beacon_time_tsf_bits)) + 49317ac9a364SKalle Valo (addon & il_beacon_time_mask_high(il, 49327ac9a364SKalle Valo il->hw_params. 49337ac9a364SKalle Valo beacon_time_tsf_bits)); 49347ac9a364SKalle Valo 49357ac9a364SKalle Valo if (base_low > addon_low) 49367ac9a364SKalle Valo res += base_low - addon_low; 49377ac9a364SKalle Valo else if (base_low < addon_low) { 49387ac9a364SKalle Valo res += interval + base_low - addon_low; 49397ac9a364SKalle Valo res += (1 << il->hw_params.beacon_time_tsf_bits); 49407ac9a364SKalle Valo } else 49417ac9a364SKalle Valo res += (1 << il->hw_params.beacon_time_tsf_bits); 49427ac9a364SKalle Valo 49437ac9a364SKalle Valo return cpu_to_le32(res); 49447ac9a364SKalle Valo } 49457ac9a364SKalle Valo EXPORT_SYMBOL(il_add_beacon_time); 49467ac9a364SKalle Valo 49477ac9a364SKalle Valo #ifdef CONFIG_PM_SLEEP 49487ac9a364SKalle Valo 49497ac9a364SKalle Valo static int 49507ac9a364SKalle Valo il_pci_suspend(struct device *device) 49517ac9a364SKalle Valo { 49527ac9a364SKalle Valo struct pci_dev *pdev = to_pci_dev(device); 49537ac9a364SKalle Valo struct il_priv *il = pci_get_drvdata(pdev); 49547ac9a364SKalle Valo 49557ac9a364SKalle Valo /* 49567ac9a364SKalle Valo * This function is called when system goes into suspend state 49577ac9a364SKalle Valo * mac80211 will call il_mac_stop() from the mac80211 suspend function 49587ac9a364SKalle Valo * first but since il_mac_stop() has no knowledge of who the caller is, 49597ac9a364SKalle Valo * it will not call apm_ops.stop() to stop the DMA operation. 49607ac9a364SKalle Valo * Calling apm_ops.stop here to make sure we stop the DMA. 49617ac9a364SKalle Valo */ 49627ac9a364SKalle Valo il_apm_stop(il); 49637ac9a364SKalle Valo 49647ac9a364SKalle Valo return 0; 49657ac9a364SKalle Valo } 49667ac9a364SKalle Valo 49677ac9a364SKalle Valo static int 49687ac9a364SKalle Valo il_pci_resume(struct device *device) 49697ac9a364SKalle Valo { 49707ac9a364SKalle Valo struct pci_dev *pdev = to_pci_dev(device); 49717ac9a364SKalle Valo struct il_priv *il = pci_get_drvdata(pdev); 49727ac9a364SKalle Valo bool hw_rfkill = false; 49737ac9a364SKalle Valo 49747ac9a364SKalle Valo /* 49757ac9a364SKalle Valo * We disable the RETRY_TIMEOUT register (0x41) to keep 49767ac9a364SKalle Valo * PCI Tx retries from interfering with C3 CPU state. 49777ac9a364SKalle Valo */ 49787ac9a364SKalle Valo pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); 49797ac9a364SKalle Valo 49807ac9a364SKalle Valo il_enable_interrupts(il); 49817ac9a364SKalle Valo 49827ac9a364SKalle Valo if (!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) 49837ac9a364SKalle Valo hw_rfkill = true; 49847ac9a364SKalle Valo 49857ac9a364SKalle Valo if (hw_rfkill) 49867ac9a364SKalle Valo set_bit(S_RFKILL, &il->status); 49877ac9a364SKalle Valo else 49887ac9a364SKalle Valo clear_bit(S_RFKILL, &il->status); 49897ac9a364SKalle Valo 49907ac9a364SKalle Valo wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill); 49917ac9a364SKalle Valo 49927ac9a364SKalle Valo return 0; 49937ac9a364SKalle Valo } 49947ac9a364SKalle Valo 49957ac9a364SKalle Valo SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume); 49967ac9a364SKalle Valo EXPORT_SYMBOL(il_pm_ops); 49977ac9a364SKalle Valo 49987ac9a364SKalle Valo #endif /* CONFIG_PM_SLEEP */ 49997ac9a364SKalle Valo 50007ac9a364SKalle Valo static void 50017ac9a364SKalle Valo il_update_qos(struct il_priv *il) 50027ac9a364SKalle Valo { 50037ac9a364SKalle Valo if (test_bit(S_EXIT_PENDING, &il->status)) 50047ac9a364SKalle Valo return; 50057ac9a364SKalle Valo 50067ac9a364SKalle Valo il->qos_data.def_qos_parm.qos_flags = 0; 50077ac9a364SKalle Valo 50087ac9a364SKalle Valo if (il->qos_data.qos_active) 50097ac9a364SKalle Valo il->qos_data.def_qos_parm.qos_flags |= 50107ac9a364SKalle Valo QOS_PARAM_FLG_UPDATE_EDCA_MSK; 50117ac9a364SKalle Valo 50127ac9a364SKalle Valo if (il->ht.enabled) 50137ac9a364SKalle Valo il->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; 50147ac9a364SKalle Valo 50157ac9a364SKalle Valo D_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", 50167ac9a364SKalle Valo il->qos_data.qos_active, il->qos_data.def_qos_parm.qos_flags); 50177ac9a364SKalle Valo 50187ac9a364SKalle Valo il_send_cmd_pdu_async(il, C_QOS_PARAM, sizeof(struct il_qosparam_cmd), 50197ac9a364SKalle Valo &il->qos_data.def_qos_parm, NULL); 50207ac9a364SKalle Valo } 50217ac9a364SKalle Valo 50227ac9a364SKalle Valo /** 50237ac9a364SKalle Valo * il_mac_config - mac80211 config callback 50247ac9a364SKalle Valo */ 50257ac9a364SKalle Valo int 50267ac9a364SKalle Valo il_mac_config(struct ieee80211_hw *hw, u32 changed) 50277ac9a364SKalle Valo { 50287ac9a364SKalle Valo struct il_priv *il = hw->priv; 50297ac9a364SKalle Valo const struct il_channel_info *ch_info; 50307ac9a364SKalle Valo struct ieee80211_conf *conf = &hw->conf; 50317ac9a364SKalle Valo struct ieee80211_channel *channel = conf->chandef.chan; 50327ac9a364SKalle Valo struct il_ht_config *ht_conf = &il->current_ht_config; 50337ac9a364SKalle Valo unsigned long flags = 0; 50347ac9a364SKalle Valo int ret = 0; 50357ac9a364SKalle Valo u16 ch; 50367ac9a364SKalle Valo int scan_active = 0; 50377ac9a364SKalle Valo bool ht_changed = false; 50387ac9a364SKalle Valo 50397ac9a364SKalle Valo mutex_lock(&il->mutex); 50407ac9a364SKalle Valo D_MAC80211("enter: channel %d changed 0x%X\n", channel->hw_value, 50417ac9a364SKalle Valo changed); 50427ac9a364SKalle Valo 50437ac9a364SKalle Valo if (unlikely(test_bit(S_SCANNING, &il->status))) { 50447ac9a364SKalle Valo scan_active = 1; 50457ac9a364SKalle Valo D_MAC80211("scan active\n"); 50467ac9a364SKalle Valo } 50477ac9a364SKalle Valo 50487ac9a364SKalle Valo if (changed & 50497ac9a364SKalle Valo (IEEE80211_CONF_CHANGE_SMPS | IEEE80211_CONF_CHANGE_CHANNEL)) { 50507ac9a364SKalle Valo /* mac80211 uses static for non-HT which is what we want */ 50517ac9a364SKalle Valo il->current_ht_config.smps = conf->smps_mode; 50527ac9a364SKalle Valo 50537ac9a364SKalle Valo /* 50547ac9a364SKalle Valo * Recalculate chain counts. 50557ac9a364SKalle Valo * 50567ac9a364SKalle Valo * If monitor mode is enabled then mac80211 will 50577ac9a364SKalle Valo * set up the SM PS mode to OFF if an HT channel is 50587ac9a364SKalle Valo * configured. 50597ac9a364SKalle Valo */ 50607ac9a364SKalle Valo if (il->ops->set_rxon_chain) 50617ac9a364SKalle Valo il->ops->set_rxon_chain(il); 50627ac9a364SKalle Valo } 50637ac9a364SKalle Valo 50647ac9a364SKalle Valo /* during scanning mac80211 will delay channel setting until 50657ac9a364SKalle Valo * scan finish with changed = 0 50667ac9a364SKalle Valo */ 50677ac9a364SKalle Valo if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { 50687ac9a364SKalle Valo 50697ac9a364SKalle Valo if (scan_active) 50707ac9a364SKalle Valo goto set_ch_out; 50717ac9a364SKalle Valo 50727ac9a364SKalle Valo ch = channel->hw_value; 50737ac9a364SKalle Valo ch_info = il_get_channel_info(il, channel->band, ch); 50747ac9a364SKalle Valo if (!il_is_channel_valid(ch_info)) { 50757ac9a364SKalle Valo D_MAC80211("leave - invalid channel\n"); 50767ac9a364SKalle Valo ret = -EINVAL; 50777ac9a364SKalle Valo goto set_ch_out; 50787ac9a364SKalle Valo } 50797ac9a364SKalle Valo 50807ac9a364SKalle Valo if (il->iw_mode == NL80211_IFTYPE_ADHOC && 50817ac9a364SKalle Valo !il_is_channel_ibss(ch_info)) { 50827ac9a364SKalle Valo D_MAC80211("leave - not IBSS channel\n"); 50837ac9a364SKalle Valo ret = -EINVAL; 50847ac9a364SKalle Valo goto set_ch_out; 50857ac9a364SKalle Valo } 50867ac9a364SKalle Valo 50877ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 50887ac9a364SKalle Valo 50897ac9a364SKalle Valo /* Configure HT40 channels */ 50907ac9a364SKalle Valo if (il->ht.enabled != conf_is_ht(conf)) { 50917ac9a364SKalle Valo il->ht.enabled = conf_is_ht(conf); 50927ac9a364SKalle Valo ht_changed = true; 50937ac9a364SKalle Valo } 50947ac9a364SKalle Valo if (il->ht.enabled) { 50957ac9a364SKalle Valo if (conf_is_ht40_minus(conf)) { 50967ac9a364SKalle Valo il->ht.extension_chan_offset = 50977ac9a364SKalle Valo IEEE80211_HT_PARAM_CHA_SEC_BELOW; 50987ac9a364SKalle Valo il->ht.is_40mhz = true; 50997ac9a364SKalle Valo } else if (conf_is_ht40_plus(conf)) { 51007ac9a364SKalle Valo il->ht.extension_chan_offset = 51017ac9a364SKalle Valo IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 51027ac9a364SKalle Valo il->ht.is_40mhz = true; 51037ac9a364SKalle Valo } else { 51047ac9a364SKalle Valo il->ht.extension_chan_offset = 51057ac9a364SKalle Valo IEEE80211_HT_PARAM_CHA_SEC_NONE; 51067ac9a364SKalle Valo il->ht.is_40mhz = false; 51077ac9a364SKalle Valo } 51087ac9a364SKalle Valo } else 51097ac9a364SKalle Valo il->ht.is_40mhz = false; 51107ac9a364SKalle Valo 51117ac9a364SKalle Valo /* 51127ac9a364SKalle Valo * Default to no protection. Protection mode will 51137ac9a364SKalle Valo * later be set from BSS config in il_ht_conf 51147ac9a364SKalle Valo */ 51157ac9a364SKalle Valo il->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; 51167ac9a364SKalle Valo 51177ac9a364SKalle Valo /* if we are switching from ht to 2.4 clear flags 51187ac9a364SKalle Valo * from any ht related info since 2.4 does not 51197ac9a364SKalle Valo * support ht */ 51207ac9a364SKalle Valo if ((le16_to_cpu(il->staging.channel) != ch)) 51217ac9a364SKalle Valo il->staging.flags = 0; 51227ac9a364SKalle Valo 51237ac9a364SKalle Valo il_set_rxon_channel(il, channel); 51247ac9a364SKalle Valo il_set_rxon_ht(il, ht_conf); 51257ac9a364SKalle Valo 51267ac9a364SKalle Valo il_set_flags_for_band(il, channel->band, il->vif); 51277ac9a364SKalle Valo 51287ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 51297ac9a364SKalle Valo 51307ac9a364SKalle Valo if (il->ops->update_bcast_stations) 51317ac9a364SKalle Valo ret = il->ops->update_bcast_stations(il); 51327ac9a364SKalle Valo 51337ac9a364SKalle Valo set_ch_out: 51347ac9a364SKalle Valo /* The list of supported rates and rate mask can be different 51357ac9a364SKalle Valo * for each band; since the band may have changed, reset 51367ac9a364SKalle Valo * the rate mask to what mac80211 lists */ 51377ac9a364SKalle Valo il_set_rate(il); 51387ac9a364SKalle Valo } 51397ac9a364SKalle Valo 51407ac9a364SKalle Valo if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { 51417ac9a364SKalle Valo il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS); 51427ac9a364SKalle Valo ret = il_power_update_mode(il, false); 51437ac9a364SKalle Valo if (ret) 51447ac9a364SKalle Valo D_MAC80211("Error setting sleep level\n"); 51457ac9a364SKalle Valo } 51467ac9a364SKalle Valo 51477ac9a364SKalle Valo if (changed & IEEE80211_CONF_CHANGE_POWER) { 51487ac9a364SKalle Valo D_MAC80211("TX Power old=%d new=%d\n", il->tx_power_user_lmt, 51497ac9a364SKalle Valo conf->power_level); 51507ac9a364SKalle Valo 51517ac9a364SKalle Valo il_set_tx_power(il, conf->power_level, false); 51527ac9a364SKalle Valo } 51537ac9a364SKalle Valo 51547ac9a364SKalle Valo if (!il_is_ready(il)) { 51557ac9a364SKalle Valo D_MAC80211("leave - not ready\n"); 51567ac9a364SKalle Valo goto out; 51577ac9a364SKalle Valo } 51587ac9a364SKalle Valo 51597ac9a364SKalle Valo if (scan_active) 51607ac9a364SKalle Valo goto out; 51617ac9a364SKalle Valo 51627ac9a364SKalle Valo if (memcmp(&il->active, &il->staging, sizeof(il->staging))) 51637ac9a364SKalle Valo il_commit_rxon(il); 51647ac9a364SKalle Valo else 51657ac9a364SKalle Valo D_INFO("Not re-sending same RXON configuration.\n"); 51667ac9a364SKalle Valo if (ht_changed) 51677ac9a364SKalle Valo il_update_qos(il); 51687ac9a364SKalle Valo 51697ac9a364SKalle Valo out: 51707ac9a364SKalle Valo D_MAC80211("leave ret %d\n", ret); 51717ac9a364SKalle Valo mutex_unlock(&il->mutex); 51727ac9a364SKalle Valo 51737ac9a364SKalle Valo return ret; 51747ac9a364SKalle Valo } 51757ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_config); 51767ac9a364SKalle Valo 51777ac9a364SKalle Valo void 51787ac9a364SKalle Valo il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 51797ac9a364SKalle Valo { 51807ac9a364SKalle Valo struct il_priv *il = hw->priv; 51817ac9a364SKalle Valo unsigned long flags; 51827ac9a364SKalle Valo 51837ac9a364SKalle Valo mutex_lock(&il->mutex); 51847ac9a364SKalle Valo D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr); 51857ac9a364SKalle Valo 51867ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 51877ac9a364SKalle Valo 51887ac9a364SKalle Valo memset(&il->current_ht_config, 0, sizeof(struct il_ht_config)); 51897ac9a364SKalle Valo 51907ac9a364SKalle Valo /* new association get rid of ibss beacon skb */ 51917ac9a364SKalle Valo if (il->beacon_skb) 51927ac9a364SKalle Valo dev_kfree_skb(il->beacon_skb); 51937ac9a364SKalle Valo il->beacon_skb = NULL; 51947ac9a364SKalle Valo il->timestamp = 0; 51957ac9a364SKalle Valo 51967ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 51977ac9a364SKalle Valo 51987ac9a364SKalle Valo il_scan_cancel_timeout(il, 100); 51997ac9a364SKalle Valo if (!il_is_ready_rf(il)) { 52007ac9a364SKalle Valo D_MAC80211("leave - not ready\n"); 52017ac9a364SKalle Valo mutex_unlock(&il->mutex); 52027ac9a364SKalle Valo return; 52037ac9a364SKalle Valo } 52047ac9a364SKalle Valo 52057ac9a364SKalle Valo /* we are restarting association process */ 52067ac9a364SKalle Valo il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 52077ac9a364SKalle Valo il_commit_rxon(il); 52087ac9a364SKalle Valo 52097ac9a364SKalle Valo il_set_rate(il); 52107ac9a364SKalle Valo 52117ac9a364SKalle Valo D_MAC80211("leave\n"); 52127ac9a364SKalle Valo mutex_unlock(&il->mutex); 52137ac9a364SKalle Valo } 52147ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_reset_tsf); 52157ac9a364SKalle Valo 52167ac9a364SKalle Valo static void 52177ac9a364SKalle Valo il_ht_conf(struct il_priv *il, struct ieee80211_vif *vif) 52187ac9a364SKalle Valo { 52197ac9a364SKalle Valo struct il_ht_config *ht_conf = &il->current_ht_config; 52207ac9a364SKalle Valo struct ieee80211_sta *sta; 52217ac9a364SKalle Valo struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 52227ac9a364SKalle Valo 52237ac9a364SKalle Valo D_ASSOC("enter:\n"); 52247ac9a364SKalle Valo 52257ac9a364SKalle Valo if (!il->ht.enabled) 52267ac9a364SKalle Valo return; 52277ac9a364SKalle Valo 52287ac9a364SKalle Valo il->ht.protection = 52297ac9a364SKalle Valo bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; 52307ac9a364SKalle Valo il->ht.non_gf_sta_present = 52317ac9a364SKalle Valo !!(bss_conf-> 52327ac9a364SKalle Valo ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 52337ac9a364SKalle Valo 52347ac9a364SKalle Valo ht_conf->single_chain_sufficient = false; 52357ac9a364SKalle Valo 52367ac9a364SKalle Valo switch (vif->type) { 52377ac9a364SKalle Valo case NL80211_IFTYPE_STATION: 52387ac9a364SKalle Valo rcu_read_lock(); 52397ac9a364SKalle Valo sta = ieee80211_find_sta(vif, bss_conf->bssid); 52407ac9a364SKalle Valo if (sta) { 52417ac9a364SKalle Valo struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; 52427ac9a364SKalle Valo int maxstreams; 52437ac9a364SKalle Valo 52447ac9a364SKalle Valo maxstreams = 52457ac9a364SKalle Valo (ht_cap->mcs. 52467ac9a364SKalle Valo tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) 52477ac9a364SKalle Valo >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 52487ac9a364SKalle Valo maxstreams += 1; 52497ac9a364SKalle Valo 52507ac9a364SKalle Valo if (ht_cap->mcs.rx_mask[1] == 0 && 52517ac9a364SKalle Valo ht_cap->mcs.rx_mask[2] == 0) 52527ac9a364SKalle Valo ht_conf->single_chain_sufficient = true; 52537ac9a364SKalle Valo if (maxstreams <= 1) 52547ac9a364SKalle Valo ht_conf->single_chain_sufficient = true; 52557ac9a364SKalle Valo } else { 52567ac9a364SKalle Valo /* 52577ac9a364SKalle Valo * If at all, this can only happen through a race 52587ac9a364SKalle Valo * when the AP disconnects us while we're still 52597ac9a364SKalle Valo * setting up the connection, in that case mac80211 52607ac9a364SKalle Valo * will soon tell us about that. 52617ac9a364SKalle Valo */ 52627ac9a364SKalle Valo ht_conf->single_chain_sufficient = true; 52637ac9a364SKalle Valo } 52647ac9a364SKalle Valo rcu_read_unlock(); 52657ac9a364SKalle Valo break; 52667ac9a364SKalle Valo case NL80211_IFTYPE_ADHOC: 52677ac9a364SKalle Valo ht_conf->single_chain_sufficient = true; 52687ac9a364SKalle Valo break; 52697ac9a364SKalle Valo default: 52707ac9a364SKalle Valo break; 52717ac9a364SKalle Valo } 52727ac9a364SKalle Valo 52737ac9a364SKalle Valo D_ASSOC("leave\n"); 52747ac9a364SKalle Valo } 52757ac9a364SKalle Valo 52767ac9a364SKalle Valo static inline void 52777ac9a364SKalle Valo il_set_no_assoc(struct il_priv *il, struct ieee80211_vif *vif) 52787ac9a364SKalle Valo { 52797ac9a364SKalle Valo /* 52807ac9a364SKalle Valo * inform the ucode that there is no longer an 52817ac9a364SKalle Valo * association and that no more packets should be 52827ac9a364SKalle Valo * sent 52837ac9a364SKalle Valo */ 52847ac9a364SKalle Valo il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 52857ac9a364SKalle Valo il->staging.assoc_id = 0; 52867ac9a364SKalle Valo il_commit_rxon(il); 52877ac9a364SKalle Valo } 52887ac9a364SKalle Valo 52897ac9a364SKalle Valo static void 52907ac9a364SKalle Valo il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 52917ac9a364SKalle Valo { 52927ac9a364SKalle Valo struct il_priv *il = hw->priv; 52937ac9a364SKalle Valo unsigned long flags; 52947ac9a364SKalle Valo __le64 timestamp; 52957ac9a364SKalle Valo struct sk_buff *skb = ieee80211_beacon_get(hw, vif); 52967ac9a364SKalle Valo 52977ac9a364SKalle Valo if (!skb) 52987ac9a364SKalle Valo return; 52997ac9a364SKalle Valo 53007ac9a364SKalle Valo D_MAC80211("enter\n"); 53017ac9a364SKalle Valo 53027ac9a364SKalle Valo lockdep_assert_held(&il->mutex); 53037ac9a364SKalle Valo 53047ac9a364SKalle Valo if (!il->beacon_enabled) { 53057ac9a364SKalle Valo IL_ERR("update beacon with no beaconing enabled\n"); 53067ac9a364SKalle Valo dev_kfree_skb(skb); 53077ac9a364SKalle Valo return; 53087ac9a364SKalle Valo } 53097ac9a364SKalle Valo 53107ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 53117ac9a364SKalle Valo 53127ac9a364SKalle Valo if (il->beacon_skb) 53137ac9a364SKalle Valo dev_kfree_skb(il->beacon_skb); 53147ac9a364SKalle Valo 53157ac9a364SKalle Valo il->beacon_skb = skb; 53167ac9a364SKalle Valo 53177ac9a364SKalle Valo timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; 53187ac9a364SKalle Valo il->timestamp = le64_to_cpu(timestamp); 53197ac9a364SKalle Valo 53207ac9a364SKalle Valo D_MAC80211("leave\n"); 53217ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 53227ac9a364SKalle Valo 53237ac9a364SKalle Valo if (!il_is_ready_rf(il)) { 53247ac9a364SKalle Valo D_MAC80211("leave - RF not ready\n"); 53257ac9a364SKalle Valo return; 53267ac9a364SKalle Valo } 53277ac9a364SKalle Valo 53287ac9a364SKalle Valo il->ops->post_associate(il); 53297ac9a364SKalle Valo } 53307ac9a364SKalle Valo 53317ac9a364SKalle Valo void 53327ac9a364SKalle Valo il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 53337ac9a364SKalle Valo struct ieee80211_bss_conf *bss_conf, u32 changes) 53347ac9a364SKalle Valo { 53357ac9a364SKalle Valo struct il_priv *il = hw->priv; 53367ac9a364SKalle Valo int ret; 53377ac9a364SKalle Valo 53387ac9a364SKalle Valo mutex_lock(&il->mutex); 53397ac9a364SKalle Valo D_MAC80211("enter: changes 0x%x\n", changes); 53407ac9a364SKalle Valo 53417ac9a364SKalle Valo if (!il_is_alive(il)) { 53427ac9a364SKalle Valo D_MAC80211("leave - not alive\n"); 53437ac9a364SKalle Valo mutex_unlock(&il->mutex); 53447ac9a364SKalle Valo return; 53457ac9a364SKalle Valo } 53467ac9a364SKalle Valo 53477ac9a364SKalle Valo if (changes & BSS_CHANGED_QOS) { 53487ac9a364SKalle Valo unsigned long flags; 53497ac9a364SKalle Valo 53507ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 53517ac9a364SKalle Valo il->qos_data.qos_active = bss_conf->qos; 53527ac9a364SKalle Valo il_update_qos(il); 53537ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 53547ac9a364SKalle Valo } 53557ac9a364SKalle Valo 53567ac9a364SKalle Valo if (changes & BSS_CHANGED_BEACON_ENABLED) { 53577ac9a364SKalle Valo /* FIXME: can we remove beacon_enabled ? */ 53587ac9a364SKalle Valo if (vif->bss_conf.enable_beacon) 53597ac9a364SKalle Valo il->beacon_enabled = true; 53607ac9a364SKalle Valo else 53617ac9a364SKalle Valo il->beacon_enabled = false; 53627ac9a364SKalle Valo } 53637ac9a364SKalle Valo 53647ac9a364SKalle Valo if (changes & BSS_CHANGED_BSSID) { 53657ac9a364SKalle Valo D_MAC80211("BSSID %pM\n", bss_conf->bssid); 53667ac9a364SKalle Valo 53677ac9a364SKalle Valo /* 53687ac9a364SKalle Valo * On passive channel we wait with blocked queues to see if 53697ac9a364SKalle Valo * there is traffic on that channel. If no frame will be 53707ac9a364SKalle Valo * received (what is very unlikely since scan detects AP on 53717ac9a364SKalle Valo * that channel, but theoretically possible), mac80211 associate 53727ac9a364SKalle Valo * procedure will time out and mac80211 will call us with NULL 53737ac9a364SKalle Valo * bssid. We have to unblock queues on such condition. 53747ac9a364SKalle Valo */ 53757ac9a364SKalle Valo if (is_zero_ether_addr(bss_conf->bssid)) 53767ac9a364SKalle Valo il_wake_queues_by_reason(il, IL_STOP_REASON_PASSIVE); 53777ac9a364SKalle Valo 53787ac9a364SKalle Valo /* 53797ac9a364SKalle Valo * If there is currently a HW scan going on in the background, 53807ac9a364SKalle Valo * then we need to cancel it, otherwise sometimes we are not 53817ac9a364SKalle Valo * able to authenticate (FIXME: why ?) 53827ac9a364SKalle Valo */ 53837ac9a364SKalle Valo if (il_scan_cancel_timeout(il, 100)) { 53847ac9a364SKalle Valo D_MAC80211("leave - scan abort failed\n"); 53857ac9a364SKalle Valo mutex_unlock(&il->mutex); 53867ac9a364SKalle Valo return; 53877ac9a364SKalle Valo } 53887ac9a364SKalle Valo 53897ac9a364SKalle Valo /* mac80211 only sets assoc when in STATION mode */ 53907ac9a364SKalle Valo memcpy(il->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); 53917ac9a364SKalle Valo 53927ac9a364SKalle Valo /* FIXME: currently needed in a few places */ 53937ac9a364SKalle Valo memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); 53947ac9a364SKalle Valo } 53957ac9a364SKalle Valo 53967ac9a364SKalle Valo /* 53977ac9a364SKalle Valo * This needs to be after setting the BSSID in case 53987ac9a364SKalle Valo * mac80211 decides to do both changes at once because 53997ac9a364SKalle Valo * it will invoke post_associate. 54007ac9a364SKalle Valo */ 54017ac9a364SKalle Valo if (vif->type == NL80211_IFTYPE_ADHOC && (changes & BSS_CHANGED_BEACON)) 54027ac9a364SKalle Valo il_beacon_update(hw, vif); 54037ac9a364SKalle Valo 54047ac9a364SKalle Valo if (changes & BSS_CHANGED_ERP_PREAMBLE) { 54057ac9a364SKalle Valo D_MAC80211("ERP_PREAMBLE %d\n", bss_conf->use_short_preamble); 54067ac9a364SKalle Valo if (bss_conf->use_short_preamble) 54077ac9a364SKalle Valo il->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; 54087ac9a364SKalle Valo else 54097ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; 54107ac9a364SKalle Valo } 54117ac9a364SKalle Valo 54127ac9a364SKalle Valo if (changes & BSS_CHANGED_ERP_CTS_PROT) { 54137ac9a364SKalle Valo D_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); 54147ac9a364SKalle Valo if (bss_conf->use_cts_prot && il->band != IEEE80211_BAND_5GHZ) 54157ac9a364SKalle Valo il->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; 54167ac9a364SKalle Valo else 54177ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; 54187ac9a364SKalle Valo if (bss_conf->use_cts_prot) 54197ac9a364SKalle Valo il->staging.flags |= RXON_FLG_SELF_CTS_EN; 54207ac9a364SKalle Valo else 54217ac9a364SKalle Valo il->staging.flags &= ~RXON_FLG_SELF_CTS_EN; 54227ac9a364SKalle Valo } 54237ac9a364SKalle Valo 54247ac9a364SKalle Valo if (changes & BSS_CHANGED_BASIC_RATES) { 54257ac9a364SKalle Valo /* XXX use this information 54267ac9a364SKalle Valo * 54277ac9a364SKalle Valo * To do that, remove code from il_set_rate() and put something 54287ac9a364SKalle Valo * like this here: 54297ac9a364SKalle Valo * 54307ac9a364SKalle Valo if (A-band) 54317ac9a364SKalle Valo il->staging.ofdm_basic_rates = 54327ac9a364SKalle Valo bss_conf->basic_rates; 54337ac9a364SKalle Valo else 54347ac9a364SKalle Valo il->staging.ofdm_basic_rates = 54357ac9a364SKalle Valo bss_conf->basic_rates >> 4; 54367ac9a364SKalle Valo il->staging.cck_basic_rates = 54377ac9a364SKalle Valo bss_conf->basic_rates & 0xF; 54387ac9a364SKalle Valo */ 54397ac9a364SKalle Valo } 54407ac9a364SKalle Valo 54417ac9a364SKalle Valo if (changes & BSS_CHANGED_HT) { 54427ac9a364SKalle Valo il_ht_conf(il, vif); 54437ac9a364SKalle Valo 54447ac9a364SKalle Valo if (il->ops->set_rxon_chain) 54457ac9a364SKalle Valo il->ops->set_rxon_chain(il); 54467ac9a364SKalle Valo } 54477ac9a364SKalle Valo 54487ac9a364SKalle Valo if (changes & BSS_CHANGED_ASSOC) { 54497ac9a364SKalle Valo D_MAC80211("ASSOC %d\n", bss_conf->assoc); 54507ac9a364SKalle Valo if (bss_conf->assoc) { 54517ac9a364SKalle Valo il->timestamp = bss_conf->sync_tsf; 54527ac9a364SKalle Valo 54537ac9a364SKalle Valo if (!il_is_rfkill(il)) 54547ac9a364SKalle Valo il->ops->post_associate(il); 54557ac9a364SKalle Valo } else 54567ac9a364SKalle Valo il_set_no_assoc(il, vif); 54577ac9a364SKalle Valo } 54587ac9a364SKalle Valo 54597ac9a364SKalle Valo if (changes && il_is_associated(il) && bss_conf->aid) { 54607ac9a364SKalle Valo D_MAC80211("Changes (%#x) while associated\n", changes); 54617ac9a364SKalle Valo ret = il_send_rxon_assoc(il); 54627ac9a364SKalle Valo if (!ret) { 54637ac9a364SKalle Valo /* Sync active_rxon with latest change. */ 54647ac9a364SKalle Valo memcpy((void *)&il->active, &il->staging, 54657ac9a364SKalle Valo sizeof(struct il_rxon_cmd)); 54667ac9a364SKalle Valo } 54677ac9a364SKalle Valo } 54687ac9a364SKalle Valo 54697ac9a364SKalle Valo if (changes & BSS_CHANGED_BEACON_ENABLED) { 54707ac9a364SKalle Valo if (vif->bss_conf.enable_beacon) { 54717ac9a364SKalle Valo memcpy(il->staging.bssid_addr, bss_conf->bssid, 54727ac9a364SKalle Valo ETH_ALEN); 54737ac9a364SKalle Valo memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); 54747ac9a364SKalle Valo il->ops->config_ap(il); 54757ac9a364SKalle Valo } else 54767ac9a364SKalle Valo il_set_no_assoc(il, vif); 54777ac9a364SKalle Valo } 54787ac9a364SKalle Valo 54797ac9a364SKalle Valo if (changes & BSS_CHANGED_IBSS) { 54807ac9a364SKalle Valo ret = il->ops->manage_ibss_station(il, vif, 54817ac9a364SKalle Valo bss_conf->ibss_joined); 54827ac9a364SKalle Valo if (ret) 54837ac9a364SKalle Valo IL_ERR("failed to %s IBSS station %pM\n", 54847ac9a364SKalle Valo bss_conf->ibss_joined ? "add" : "remove", 54857ac9a364SKalle Valo bss_conf->bssid); 54867ac9a364SKalle Valo } 54877ac9a364SKalle Valo 54887ac9a364SKalle Valo D_MAC80211("leave\n"); 54897ac9a364SKalle Valo mutex_unlock(&il->mutex); 54907ac9a364SKalle Valo } 54917ac9a364SKalle Valo EXPORT_SYMBOL(il_mac_bss_info_changed); 54927ac9a364SKalle Valo 54937ac9a364SKalle Valo irqreturn_t 54947ac9a364SKalle Valo il_isr(int irq, void *data) 54957ac9a364SKalle Valo { 54967ac9a364SKalle Valo struct il_priv *il = data; 54977ac9a364SKalle Valo u32 inta, inta_mask; 54987ac9a364SKalle Valo u32 inta_fh; 54997ac9a364SKalle Valo unsigned long flags; 55007ac9a364SKalle Valo if (!il) 55017ac9a364SKalle Valo return IRQ_NONE; 55027ac9a364SKalle Valo 55037ac9a364SKalle Valo spin_lock_irqsave(&il->lock, flags); 55047ac9a364SKalle Valo 55057ac9a364SKalle Valo /* Disable (but don't clear!) interrupts here to avoid 55067ac9a364SKalle Valo * back-to-back ISRs and sporadic interrupts from our NIC. 55077ac9a364SKalle Valo * If we have something to service, the tasklet will re-enable ints. 55087ac9a364SKalle Valo * If we *don't* have something, we'll re-enable before leaving here. */ 55097ac9a364SKalle Valo inta_mask = _il_rd(il, CSR_INT_MASK); /* just for debug */ 55107ac9a364SKalle Valo _il_wr(il, CSR_INT_MASK, 0x00000000); 55117ac9a364SKalle Valo 55127ac9a364SKalle Valo /* Discover which interrupts are active/pending */ 55137ac9a364SKalle Valo inta = _il_rd(il, CSR_INT); 55147ac9a364SKalle Valo inta_fh = _il_rd(il, CSR_FH_INT_STATUS); 55157ac9a364SKalle Valo 55167ac9a364SKalle Valo /* Ignore interrupt if there's nothing in NIC to service. 55177ac9a364SKalle Valo * This may be due to IRQ shared with another device, 55187ac9a364SKalle Valo * or due to sporadic interrupts thrown from our NIC. */ 55197ac9a364SKalle Valo if (!inta && !inta_fh) { 55207ac9a364SKalle Valo D_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); 55217ac9a364SKalle Valo goto none; 55227ac9a364SKalle Valo } 55237ac9a364SKalle Valo 55247ac9a364SKalle Valo if (inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0) { 55257ac9a364SKalle Valo /* Hardware disappeared. It might have already raised 55267ac9a364SKalle Valo * an interrupt */ 55277ac9a364SKalle Valo IL_WARN("HARDWARE GONE?? INTA == 0x%08x\n", inta); 55287ac9a364SKalle Valo goto unplugged; 55297ac9a364SKalle Valo } 55307ac9a364SKalle Valo 55317ac9a364SKalle Valo D_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, 55327ac9a364SKalle Valo inta_fh); 55337ac9a364SKalle Valo 55347ac9a364SKalle Valo inta &= ~CSR_INT_BIT_SCD; 55357ac9a364SKalle Valo 55367ac9a364SKalle Valo /* il_irq_tasklet() will service interrupts and re-enable them */ 55377ac9a364SKalle Valo if (likely(inta || inta_fh)) 55387ac9a364SKalle Valo tasklet_schedule(&il->irq_tasklet); 55397ac9a364SKalle Valo 55407ac9a364SKalle Valo unplugged: 55417ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 55427ac9a364SKalle Valo return IRQ_HANDLED; 55437ac9a364SKalle Valo 55447ac9a364SKalle Valo none: 55457ac9a364SKalle Valo /* re-enable interrupts here since we don't have anything to service. */ 55467ac9a364SKalle Valo /* only Re-enable if disabled by irq */ 55477ac9a364SKalle Valo if (test_bit(S_INT_ENABLED, &il->status)) 55487ac9a364SKalle Valo il_enable_interrupts(il); 55497ac9a364SKalle Valo spin_unlock_irqrestore(&il->lock, flags); 55507ac9a364SKalle Valo return IRQ_NONE; 55517ac9a364SKalle Valo } 55527ac9a364SKalle Valo EXPORT_SYMBOL(il_isr); 55537ac9a364SKalle Valo 55547ac9a364SKalle Valo /* 55557ac9a364SKalle Valo * il_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this 55567ac9a364SKalle Valo * function. 55577ac9a364SKalle Valo */ 55587ac9a364SKalle Valo void 55597ac9a364SKalle Valo il_tx_cmd_protection(struct il_priv *il, struct ieee80211_tx_info *info, 55607ac9a364SKalle Valo __le16 fc, __le32 *tx_flags) 55617ac9a364SKalle Valo { 55627ac9a364SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { 55637ac9a364SKalle Valo *tx_flags |= TX_CMD_FLG_RTS_MSK; 55647ac9a364SKalle Valo *tx_flags &= ~TX_CMD_FLG_CTS_MSK; 55657ac9a364SKalle Valo *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; 55667ac9a364SKalle Valo 55677ac9a364SKalle Valo if (!ieee80211_is_mgmt(fc)) 55687ac9a364SKalle Valo return; 55697ac9a364SKalle Valo 55707ac9a364SKalle Valo switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { 55717ac9a364SKalle Valo case cpu_to_le16(IEEE80211_STYPE_AUTH): 55727ac9a364SKalle Valo case cpu_to_le16(IEEE80211_STYPE_DEAUTH): 55737ac9a364SKalle Valo case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): 55747ac9a364SKalle Valo case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): 55757ac9a364SKalle Valo *tx_flags &= ~TX_CMD_FLG_RTS_MSK; 55767ac9a364SKalle Valo *tx_flags |= TX_CMD_FLG_CTS_MSK; 55777ac9a364SKalle Valo break; 55787ac9a364SKalle Valo } 55797ac9a364SKalle Valo } else if (info->control.rates[0]. 55807ac9a364SKalle Valo flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 55817ac9a364SKalle Valo *tx_flags &= ~TX_CMD_FLG_RTS_MSK; 55827ac9a364SKalle Valo *tx_flags |= TX_CMD_FLG_CTS_MSK; 55837ac9a364SKalle Valo *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; 55847ac9a364SKalle Valo } 55857ac9a364SKalle Valo } 55867ac9a364SKalle Valo EXPORT_SYMBOL(il_tx_cmd_protection); 5587