]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
[karo-tx-linux.git] / drivers / net / wireless / iwlwifi / iwl-trans-pcie.c
index 4d7b30d3e64855e83b03d1cfaaa4391d6fa8b8d4..9f62283504e35b046ab277e14d127e882949184f 100644 (file)
@@ -180,7 +180,6 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
                           FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
                           FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
                           FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
                           rb_size|
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
@@ -370,21 +369,13 @@ error:
 }
 
 static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                     int slots_num, u32 txq_id)
+                             int slots_num, u32 txq_id)
 {
        int ret;
 
        txq->need_update = 0;
        memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
 
-       /*
-        * For the default queues 0-3, set up the swq_id
-        * already -- all others need to get one later
-        * (if they need one at all).
-        */
-       if (txq_id < 4)
-               iwl_set_swq_id(txq, txq_id, txq_id);
-
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
         * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
        BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -895,59 +886,6 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
        return ret;
 }
 
-#define IWL_AC_UNSET -1
-
-struct queue_to_fifo_ac {
-       s8 fifo, ac;
-};
-
-static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
-       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-};
-
-static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
-       { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
-       { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_BE_IPAN, 2, },
-       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
-};
-
-static const u8 iwlagn_bss_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-static const u8 iwlagn_bss_ac_to_queue[] = {
-       0, 1, 2, 3,
-};
-static const u8 iwlagn_pan_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO_IPAN,
-       IWL_TX_FIFO_VI_IPAN,
-       IWL_TX_FIFO_BE_IPAN,
-       IWL_TX_FIFO_BK_IPAN,
-};
-static const u8 iwlagn_pan_ac_to_queue[] = {
-       7, 6, 5, 4,
-};
-
 /*
  * ucode
  */
@@ -1028,19 +966,8 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                                   const struct fw_img *fw)
 {
        int ret;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill;
 
-       trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
-       trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
-
-       trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
-       trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
-
-       trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
-       trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
-
        /* This may fail if AMT took ownership of the device */
        if (iwl_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
@@ -1098,9 +1025,7 @@ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
 
 static void iwl_tx_start(struct iwl_trans *trans)
 {
-       const struct queue_to_fifo_ac *queue_to_fifo;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 a;
        unsigned long flags;
        int i, chan;
@@ -1166,41 +1091,19 @@ static void iwl_tx_start(struct iwl_trans *trans)
        /* Activate all Tx DMA/FIFO channels */
        iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
 
-       /* map queues to FIFOs */
-       if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
-               queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
-       else
-               queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-
        iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
 
-       /* make sure all queue are not stopped */
-       memset(&trans_pcie->queue_stopped[0], 0,
-               sizeof(trans_pcie->queue_stopped));
-       for (i = 0; i < 4; i++)
-               atomic_set(&trans_pcie->queue_stop_count[i], 0);
+       /* make sure all queue are not stopped/used */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
 
-       /* reset to 0 to enable all the queue first */
-       trans_pcie->txq_ctx_active_msk = 0;
+       for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
+               int fifo = trans_pcie->setup_q_to_fifo[i];
 
-       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
-                                               IWLAGN_FIRST_AMPDU_QUEUE);
-       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
-                                               IWLAGN_FIRST_AMPDU_QUEUE);
+               set_bit(i, trans_pcie->queue_used);
 
-       for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
-               int fifo = queue_to_fifo[i].fifo;
-               int ac = queue_to_fifo[i].ac;
-
-               iwl_txq_ctx_activate(trans_pcie, i);
-
-               if (fifo == IWL_TX_FIFO_UNUSED)
-                       continue;
-
-               if (ac != IWL_AC_UNSET)
-                       iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
                iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
-                                             fifo, 0);
+                                             fifo, true);
        }
 
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -1325,70 +1228,32 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
 }
 
 static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
-               struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
-               u8 sta_id, u8 tid)
+                            struct iwl_device_cmd *dev_cmd, int txq_id)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
        struct iwl_cmd_meta *out_meta;
        struct iwl_tx_queue *txq;
        struct iwl_queue *q;
-
        dma_addr_t phys_addr = 0;
        dma_addr_t txcmd_phys;
        dma_addr_t scratch_phys;
        u16 len, firstlen, secondlen;
        u8 wait_write_ptr = 0;
-       u8 txq_id;
-       bool is_agg = false;
        __le16 fc = hdr->frame_control;
        u8 hdr_len = ieee80211_hdrlen(fc);
        u16 __maybe_unused wifi_seq;
 
-       /*
-        * Send this frame after DTIM -- there's a special queue
-        * reserved for this for contexts that support AP mode.
-        */
-       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-               txq_id = trans_pcie->mcast_queue[ctx];
-
-               /*
-                * The microcode will clear the more data
-                * bit in the last frame it transmits.
-                */
-               hdr->frame_control |=
-                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-               txq_id = IWL_AUX_QUEUE;
-       else
-               txq_id =
-                   trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
-
-       /* aggregation is on for this <sta,tid> */
-       if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-               WARN_ON(tid >= IWL_MAX_TID_COUNT);
-               txq_id = trans_pcie->agg_txq[sta_id][tid];
-               is_agg = true;
-       }
-
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
 
-       spin_lock(&txq->lock);
+       if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
 
-       /* In AGG mode, the index in the ring must correspond to the WiFi
-        * sequence number. This is a HW requirements to help the SCD to parse
-        * the BA.
-        * Check here that the packets are in the right place on the ring.
-        */
-#ifdef CONFIG_IWLWIFI_DEBUG
-       wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
-       WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr),
-                 "Q: %d WiFi Seq %d tfdNum %d",
-                 txq_id, wifi_seq, q->write_ptr);
-#endif
+       spin_lock(&txq->lock);
 
        /* Set up driver data for this TFD */
        txq->skbs[q->write_ptr] = skb;
@@ -1565,8 +1430,8 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
        iwl_enable_rfkill_int(trans);
 }
 
-static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
-                     int txq_id, int ssn, struct sk_buff_head *skbs)
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+                                  struct sk_buff_head *skbs)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
@@ -1578,33 +1443,15 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
 
        txq->time_stamp = jiffies;
 
-       if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
-                    tid != IWL_TID_NON_QOS &&
-                    txq_id != trans_pcie->agg_txq[sta_id][tid])) {
-               /*
-                * FIXME: this is a uCode bug which need to be addressed,
-                * log the information and return for now.
-                * Since it is can possibly happen very often and in order
-                * not to fill the syslog, don't use IWL_ERR or IWL_WARN
-                */
-               IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, "
-                       "agg_txq[sta_id[tid] %d", txq_id,
-                       trans_pcie->agg_txq[sta_id][tid]);
-               spin_unlock(&txq->lock);
-               return 1;
-       }
-
        if (txq->q.read_ptr != tfd_num) {
-               IWL_DEBUG_TX_REPLY(trans, "[Q %d | AC %d] %d -> %d (%d)\n",
-                               txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
-                               tfd_num, ssn);
+               IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
+                                  txq_id, txq->q.read_ptr, tfd_num, ssn);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark)
                        iwl_wake_queue(trans, txq);
        }
 
        spin_unlock(&txq->lock);
-       return 0;
 }
 
 static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@ -1623,7 +1470,7 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
 }
 
 static void iwl_trans_pcie_configure(struct iwl_trans *trans,
-                             const struct iwl_trans_config *trans_cfg)
+                                    const struct iwl_trans_config *trans_cfg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -1635,6 +1482,17 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
        if (trans_pcie->n_no_reclaim_cmds)
                memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
                       trans_pcie->n_no_reclaim_cmds * sizeof(u8));
+
+       trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
+
+       if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
+               trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
+
+       /* at least the command queue must be mapped */
+       WARN_ON(!trans_pcie->n_q_to_fifo);
+
+       memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
+              trans_pcie->n_q_to_fifo * sizeof(u8));
 }
 
 static void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1660,6 +1518,16 @@ static void iwl_trans_pcie_free(struct iwl_trans *trans)
        kfree(trans);
 }
 
+static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (state)
+               set_bit(STATUS_POWER_PMI, &trans_pcie->status);
+       else
+               clear_bit(STATUS_POWER_PMI, &trans_pcie->status);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
 {
@@ -1952,18 +1820,10 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
                txq = &trans_pcie->txq[cnt];
                q = &txq->q;
                pos += scnprintf(buf + pos, bufsz - pos,
-                               "hwq %.2d: read=%u write=%u stop=%d"
-                               " swq_id=%#.2x (ac %d/hwq %d)\n",
+                               "hwq %.2d: read=%u write=%u use=%d stop=%d\n",
                                cnt, q->read_ptr, q->write_ptr,
-                               !!test_bit(cnt, trans_pcie->queue_stopped),
-                               txq->swq_id, txq->swq_id & 3,
-                               (txq->swq_id >> 2) & 0x1f);
-               if (cnt >= 4)
-                       continue;
-               /* for the ACs, display the stop count too */
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "        stop-count: %d\n",
-                       atomic_read(&trans_pcie->queue_stop_count[cnt]));
+                               !!test_bit(cnt, trans_pcie->queue_used),
+                               !!test_bit(cnt, trans_pcie->queue_stopped));
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
@@ -1997,44 +1857,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
-static ssize_t iwl_dbgfs_log_event_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char *buf;
-       int pos = 0;
-       ssize_t ret = -ENOMEM;
-
-       ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true);
-       if (buf) {
-               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-               kfree(buf);
-       }
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_log_event_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       u32 event_log_flag;
-       char buf[8];
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &event_log_flag) != 1)
-               return -EFAULT;
-       if (event_log_flag == 1)
-               iwl_dump_nic_event_log(trans, true, NULL, false);
-
-       return count;
-}
-
 static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
@@ -2161,7 +1983,6 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
        return ret;
 }
 
-DEBUGFS_READ_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 DEBUGFS_READ_FILE_OPS(fh_reg);
 DEBUGFS_READ_FILE_OPS(rx_queue);
@@ -2177,7 +1998,6 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
 {
        DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
        DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
@@ -2205,7 +2025,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .reclaim = iwl_trans_pcie_reclaim,
 
        .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
-       .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
        .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
 
        .free = iwl_trans_pcie_free,
@@ -2223,6 +2042,7 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .write32 = iwl_trans_pcie_write32,
        .read32 = iwl_trans_pcie_read32,
        .configure = iwl_trans_pcie_configure,
+       .set_pmi = iwl_trans_pcie_set_pmi,
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,