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