]> Pileus Git - ~andy/linux/blobdiff - drivers/net/wireless/iwlwifi/iwl-rx.c
Merge branch 'master' of git://git.infradead.org/users/linville/wireless-next into...
[~andy/linux] / drivers / net / wireless / iwlwifi / iwl-rx.c
index 37bc017b80ac0877cb029c53926c11f38bb98204..bcd7f64683aa02c06ebd1af0e8650ef39d8fdd11 100644 (file)
 #include "iwl-agn.h"
 #include "iwl-shared.h"
 
+const char *get_cmd_string(u8 cmd)
+{
+       switch (cmd) {
+               IWL_CMD(REPLY_ALIVE);
+               IWL_CMD(REPLY_ERROR);
+               IWL_CMD(REPLY_RXON);
+               IWL_CMD(REPLY_RXON_ASSOC);
+               IWL_CMD(REPLY_QOS_PARAM);
+               IWL_CMD(REPLY_RXON_TIMING);
+               IWL_CMD(REPLY_ADD_STA);
+               IWL_CMD(REPLY_REMOVE_STA);
+               IWL_CMD(REPLY_REMOVE_ALL_STA);
+               IWL_CMD(REPLY_TXFIFO_FLUSH);
+               IWL_CMD(REPLY_WEPKEY);
+               IWL_CMD(REPLY_TX);
+               IWL_CMD(REPLY_LEDS_CMD);
+               IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+               IWL_CMD(COEX_PRIORITY_TABLE_CMD);
+               IWL_CMD(COEX_MEDIUM_NOTIFICATION);
+               IWL_CMD(COEX_EVENT_CMD);
+               IWL_CMD(REPLY_QUIET_CMD);
+               IWL_CMD(REPLY_CHANNEL_SWITCH);
+               IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+               IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+               IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+               IWL_CMD(POWER_TABLE_CMD);
+               IWL_CMD(PM_SLEEP_NOTIFICATION);
+               IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+               IWL_CMD(REPLY_SCAN_CMD);
+               IWL_CMD(REPLY_SCAN_ABORT_CMD);
+               IWL_CMD(SCAN_START_NOTIFICATION);
+               IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+               IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+               IWL_CMD(BEACON_NOTIFICATION);
+               IWL_CMD(REPLY_TX_BEACON);
+               IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+               IWL_CMD(QUIET_NOTIFICATION);
+               IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+               IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+               IWL_CMD(REPLY_BT_CONFIG);
+               IWL_CMD(REPLY_STATISTICS_CMD);
+               IWL_CMD(STATISTICS_NOTIFICATION);
+               IWL_CMD(REPLY_CARD_STATE_CMD);
+               IWL_CMD(CARD_STATE_NOTIFICATION);
+               IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+               IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+               IWL_CMD(SENSITIVITY_CMD);
+               IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+               IWL_CMD(REPLY_RX_PHY_CMD);
+               IWL_CMD(REPLY_RX_MPDU_CMD);
+               IWL_CMD(REPLY_RX);
+               IWL_CMD(REPLY_COMPRESSED_BA);
+               IWL_CMD(CALIBRATION_CFG_CMD);
+               IWL_CMD(CALIBRATION_RES_NOTIFICATION);
+               IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
+               IWL_CMD(REPLY_TX_POWER_DBM_CMD);
+               IWL_CMD(TEMPERATURE_NOTIFICATION);
+               IWL_CMD(TX_ANT_CONFIGURATION_CMD);
+               IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
+               IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
+               IWL_CMD(REPLY_BT_COEX_PROT_ENV);
+               IWL_CMD(REPLY_WIPAN_PARAMS);
+               IWL_CMD(REPLY_WIPAN_RXON);
+               IWL_CMD(REPLY_WIPAN_RXON_TIMING);
+               IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
+               IWL_CMD(REPLY_WIPAN_QOS_PARAM);
+               IWL_CMD(REPLY_WIPAN_WEPKEY);
+               IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
+               IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
+               IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE);
+               IWL_CMD(REPLY_WOWLAN_PATTERNS);
+               IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER);
+               IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS);
+               IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS);
+               IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL);
+               IWL_CMD(REPLY_WOWLAN_GET_STATUS);
+       default:
+               return "UNKNOWN";
+
+       }
+}
 
 /******************************************************************************
  *
  *
  ******************************************************************************/
 
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_error(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
@@ -61,9 +143,11 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
                pkt->u.err_resp.cmd_id,
                le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
                le32_to_cpu(pkt->u.err_resp.error_info));
+       return 0;
 }
 
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
@@ -75,7 +159,7 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
        if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
-               return;
+               return 0;
 
        if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
                rxon->channel = csa->channel;
@@ -88,11 +172,13 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                        le16_to_cpu(csa->channel));
                iwl_chswitch_done(priv, false);
        }
+       return 0;
 }
 
 
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+                                         struct iwl_rx_mem_buffer *rxb,
+                                         struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
@@ -100,15 +186,17 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
        if (!report->state) {
                IWL_DEBUG_11H(priv,
                        "Spectrum Measure Notification: Start\n");
-               return;
+               return 0;
        }
 
        memcpy(&priv->measure_report, report, sizeof(*report));
        priv->measurement_status |= MEASUREMENT_READY;
+       return 0;
 }
 
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -116,21 +204,26 @@ static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
        IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
                     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
+       return 0;
 }
 
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                            struct iwl_rx_mem_buffer *rxb,
+                                            struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       u32 __maybe_unused len =
+               le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
        IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
                        "notification for %s:\n", len,
                        get_cmd_string(pkt->hdr.cmd));
        iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
+       return 0;
 }
 
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw;
@@ -151,6 +244,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 
        if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
                queue_work(priv->shrd->workqueue, &priv->beacon_update);
+       return 0;
 }
 
 /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
@@ -393,8 +487,9 @@ iwl_accumulative_statistics(struct iwl_priv *priv,
 }
 #endif
 
-static void iwl_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb,
+                             struct iwl_device_cmd *cmd)
 {
        unsigned long stamp = jiffies;
        const int reg_recalib_period = 60;
@@ -448,7 +543,7 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
                WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
                          len, sizeof(struct iwl_bt_notif_statistics),
                          sizeof(struct iwl_notif_statistics));
-               return;
+               return 0;
        }
 
        change = common->temperature != priv->statistics.common.temperature ||
@@ -491,10 +586,12 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
        }
        if (priv->cfg->lib->temperature && change)
                priv->cfg->lib->temperature(priv);
+       return 0;
 }
 
-static void iwl_rx_reply_statistics(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_statistics(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
@@ -509,13 +606,15 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
 #endif
                IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
        }
-       iwl_rx_statistics(priv, rxb);
+       iwl_rx_statistics(priv, rxb, cmd);
+       return 0;
 }
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_card_state_notif(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
@@ -530,16 +629,16 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
        if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
                     CT_CARD_DISABLED)) {
 
-               iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+               iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
                            CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
-               iwl_write_direct32(priv, HBUS_TARG_MBX_C,
+               iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C,
                                        HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
                if (!(flags & RXON_CARD_DISABLED)) {
-                       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
                                    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-                       iwl_write_direct32(priv, HBUS_TARG_MBX_C,
+                       iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C,
                                        HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
                }
                if (flags & CT_CARD_DISABLED)
@@ -562,11 +661,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->shrd->wait_command_queue);
+       return 0;
 }
 
-static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_device_cmd *cmd)
 
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -584,18 +685,21 @@ static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                if (!test_bit(STATUS_SCANNING, &priv->shrd->status))
                        iwl_init_sensitivity(priv);
        }
+       return 0;
 }
 
 /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
  * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_rx_phy(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
        priv->last_phy_res_valid = true;
        memcpy(&priv->last_phy_res, pkt->u.raw,
               sizeof(struct iwl_rx_phy_res));
+       return 0;
 }
 
 /*
@@ -698,7 +802,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
                                               ctx->active.bssid_addr))
                                continue;
                        ctx->last_tx_rejected = false;
-                       iwl_wake_any_queue(priv, ctx);
+                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid);
                }
        }
 
@@ -810,8 +914,9 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
 
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl_rx_reply_rx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_rx(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_device_cmd *cmd)
 {
        struct ieee80211_hdr *header;
        struct ieee80211_rx_status rx_status;
@@ -844,7 +949,7 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
        } else {
                if (!priv->last_phy_res_valid) {
                        IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-                       return;
+                       return 0;
                }
                phy_res = &priv->last_phy_res;
                amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw;
@@ -858,14 +963,14 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
        if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
                IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
                                phy_res->cfg_phy_cnt);
-               return;
+               return 0;
        }
 
        if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
            !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
                IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
                                le32_to_cpu(rx_pkt_status));
-               return;
+               return 0;
        }
 
        /* This will be used in several places later */
@@ -926,6 +1031,7 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
 
        iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
                                    rxb, &rx_status);
+       return 0;
 }
 
 /**
@@ -936,7 +1042,8 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
  */
 void iwl_setup_rx_handlers(struct iwl_priv *priv)
 {
-       void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
 
        handlers = priv->rx_handlers;
 
@@ -946,6 +1053,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        handlers[PM_SLEEP_NOTIFICATION]         = iwl_rx_pm_sleep_notif;
        handlers[PM_DEBUG_STATISTIC_NOTIFIC]    = iwl_rx_pm_debug_statistics_notif;
        handlers[BEACON_NOTIFICATION]           = iwl_rx_beacon_notif;
+       handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
 
        /*
         * The same handler is used for both the REPLY to a discrete
@@ -983,9 +1091,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
 
 }
 
-void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       int err = 0;
 
        /*
         * Do the notification wait before RX handlers so
@@ -1019,12 +1129,13 @@ void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
         *   handle those that need handling via function in
         *   rx_handlers table.  See iwl_setup_rx_handlers() */
        if (priv->rx_handlers[pkt->hdr.cmd]) {
-               priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
-               priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+               priv->rx_handlers_stats[pkt->hdr.cmd]++;
+               err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
        } else {
                /* No handling needed */
                IWL_DEBUG_RX(priv,
                        "No handler needed for %s, 0x%02x\n",
                        get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
        }
+       return err;
 }