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