iwlwifi: the read / write register ops move to transport
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-trans-pcie.c
index 5f17ab8e76bacbc7e4521951c15a716a532afc45..80f531844f3eb5b6da24ff14ff56047159a89675 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/interrupt.h>
 #include <linux/debugfs.h>
 #include <linux/bitops.h>
@@ -88,18 +90,16 @@ static int iwl_trans_rx_alloc(struct iwl_trans *trans)
                return -EINVAL;
 
        /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                    &rxq->bd_dma, GFP_KERNEL);
+       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                                     &rxq->bd_dma, GFP_KERNEL);
        if (!rxq->bd)
                goto err_bd;
-       memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
 
        /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                         &rxq->rb_stts_dma, GFP_KERNEL);
+       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                          &rxq->rb_stts_dma, GFP_KERNEL);
        if (!rxq->rb_stts)
                goto err_rb_stts;
-       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
 
        return 0;
 
@@ -649,8 +649,10 @@ static int iwl_nic_init(struct iwl_trans *trans)
 
        iwl_nic_config(priv(trans));
 
+#ifndef CONFIG_IWLWIFI_IDI
        /* Allocate the RX queue, or reset if it is already allocated */
        iwl_rx_init(trans);
+#endif
 
        /* Allocate or reset and init all Tx and Command queues */
        if (iwl_tx_init(trans))
@@ -837,7 +839,7 @@ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
        iwl_write_prph(bus(trans), SCD_TXFACT, mask);
 }
 
-static void iwl_trans_pcie_tx_start(struct iwl_trans *trans)
+static void iwl_tx_start(struct iwl_trans *trans)
 {
        const struct queue_to_fifo_ac *queue_to_fifo;
        struct iwl_trans_pcie *trans_pcie =
@@ -950,6 +952,12 @@ static void iwl_trans_pcie_tx_start(struct iwl_trans *trans)
                          APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 }
 
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
+{
+       iwl_reset_ict(trans);
+       iwl_tx_start(trans);
+}
+
 /**
  * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
  */
@@ -1012,8 +1020,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         */
        if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) {
                iwl_trans_tx_stop(trans);
+#ifndef CONFIG_IWLWIFI_IDI
                iwl_trans_rx_stop(trans);
-
+#endif
                /* Power-down device's busmaster DMA clocks */
                iwl_write_prph(bus(trans), APMG_CLK_DIS_REG,
                               APMG_CLK_VAL_DMA_CLK_RQT);
@@ -1035,7 +1044,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        spin_unlock_irqrestore(&trans->shrd->lock, flags);
 
        /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(bus(trans)->irq);
+       synchronize_irq(trans->irq);
        tasklet_kill(&trans_pcie->irq_tasklet);
 
        /* stop and reset the on-board processor */
@@ -1044,7 +1053,7 @@ static void iwl_trans_pcie_stop_device(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 sta_id, u8 tid)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -1058,13 +1067,12 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        dma_addr_t txcmd_phys;
        dma_addr_t scratch_phys;
        u16 len, firstlen, secondlen;
-       u16 seq_number = 0;
        u8 wait_write_ptr = 0;
        u8 txq_id;
-       u8 tid = 0;
        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
@@ -1085,36 +1093,28 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                txq_id =
                    trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
 
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-               u8 *qc = NULL;
-               struct iwl_tid_data *tid_data;
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               tid_data = &trans->shrd->tid_data[sta_id][tid];
-
-               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
-                       return -1;
-
-               seq_number = tid_data->seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = hdr->seq_ctrl &
-                               cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               seq_number += 0x10;
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON);
-                       txq_id = tid_data->agg.txq_id;
-                       is_agg = true;
-               }
+       /* 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;
        }
 
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
-
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
 
+       /* 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
+
        /* Set up driver data for this TFD */
        txq->skbs[q->write_ptr] = skb;
        txq->cmd[q->write_ptr] = dev_cmd;
@@ -1212,13 +1212,6 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
        iwl_txq_update_write_ptr(trans, txq);
 
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
-               if (!ieee80211_has_morefrags(fc))
-                       trans->shrd->tid_data[sta_id][tid].seq_number =
-                               seq_number;
-       }
-
        /*
         * At this point the frame is "transmitted" successfully
         * and we will get a TX status notification eventually,
@@ -1230,7 +1223,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                        txq->need_update = 1;
                        iwl_txq_update_write_ptr(trans, txq);
                } else {
-                       iwl_stop_queue(trans, txq);
+                       iwl_stop_queue(trans, txq, "Queue is full");
                }
        }
        return 0;
@@ -1255,10 +1248,10 @@ static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
 
        iwl_alloc_isr_ict(trans);
 
-       err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED,
+       err = request_irq(trans->irq, iwl_isr_ict, IRQF_SHARED,
                DRV_NAME, trans);
        if (err) {
-               IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq);
+               IWL_ERR(trans, "Error allocating IRQ %d\n", trans->irq);
                iwl_free_isr_ict(trans);
                return err;
        }
@@ -1267,105 +1260,79 @@ static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
        return 0;
 }
 
-static int iwlagn_txq_check_empty(struct iwl_trans *trans,
-                          int sta_id, u8 tid, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_queue *q = &trans_pcie->txq[txq_id].q;
-       struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid];
-
-       lockdep_assert_held(&trans->shrd->sta_lock);
-
-       switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if ((txq_id  == tid_data->agg.txq_id) &&
-                   (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_HT(trans,
-                               "HW queue empty: continue DELBA flow\n");
-                       iwl_trans_pcie_txq_agg_disable(trans, txq_id);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       iwl_stop_tx_ba_trans_ready(priv(trans),
-                                                  NUM_IWL_RXON_CTX,
-                                                  sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(trans,
-                               "HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       iwl_start_tx_ba_trans_ready(priv(trans),
-                                                   NUM_IWL_RXON_CTX,
-                                                   sta_id, tid);
-               }
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
-                           int sta_id, int tid, int freed)
-{
-       lockdep_assert_held(&trans->shrd->sta_lock);
-
-       if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
-       else {
-               IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
-                       trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
-                       freed);
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
-       }
-}
-
-static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
+static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                      int txq_id, int ssn, u32 status,
                      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];
-       enum iwl_agg_state agg_state;
        /* n_bd is usually 256 => n_bd - 1 = 0xff */
        int tfd_num = ssn & (txq->q.n_bd - 1);
        int freed = 0;
-       bool cond;
 
        txq->time_stamp = jiffies;
 
-       if (txq->sched_retry) {
-               agg_state =
-                       trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state;
-               cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
-       } else {
-               cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
+       if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
+                    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]);
+               return 1;
        }
 
        if (txq->q.read_ptr != tfd_num) {
-               IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
-                               "scd_ssn=%d idx=%d txq=%d swq=%d\n",
-                               ssn , tfd_num, txq_id, txq->swq_id);
+               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);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
-                       iwl_wake_queue(trans, txq);
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                  (!txq->sched_retry ||
+                  status != TX_STATUS_FAIL_PASSIVE_NO_RX))
+                       iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
+       return 0;
+}
+
+static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
+{
+       iowrite8(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
+{
+       iowrite32(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
 
-       iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
-       iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
+static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
+{
+       u32 val = ioread32(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+       return val;
 }
 
 static void iwl_trans_pcie_free(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_calib_free_results(trans);
        iwl_trans_pcie_tx_free(trans);
+#ifndef CONFIG_IWLWIFI_IDI
        iwl_trans_pcie_rx_free(trans);
-       free_irq(bus(trans)->irq, trans);
+#endif
+       free_irq(trans->irq, trans);
        iwl_free_isr_ict(trans);
+
+       pci_disable_msi(trans_pcie->pci_dev);
+       pci_iounmap(trans_pcie->pci_dev, trans_pcie->hw_base);
+       pci_release_regions(trans_pcie->pci_dev);
+       pci_disable_device(trans_pcie->pci_dev);
+
        trans->shrd->trans = NULL;
        kfree(trans);
 }
@@ -1417,7 +1384,8 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 #endif /* CONFIG_PM_SLEEP */
 
 static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         enum iwl_rxon_context_id ctx)
+                                         enum iwl_rxon_context_id ctx,
+                                         const char *msg)
 {
        u8 ac, txq_id;
        struct iwl_trans_pcie *trans_pcie =
@@ -1425,38 +1393,20 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
 
        for (ac = 0; ac < AC_NUM; ac++) {
                txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
+               IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
                        ac,
                        (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
                              ? "stopped" : "awake");
-               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+               iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
        }
 }
 
-const struct iwl_trans_ops trans_ops_pcie;
-
-static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
-{
-       struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) +
-                                             sizeof(struct iwl_trans_pcie),
-                                             GFP_KERNEL);
-       if (iwl_trans) {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
-               iwl_trans->ops = &trans_ops_pcie;
-               iwl_trans->shrd = shrd;
-               trans_pcie->trans = iwl_trans;
-               spin_lock_init(&iwl_trans->hcmd_lock);
-       }
-
-       return iwl_trans;
-}
-
-static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
+                                     const char *msg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+       iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
 }
 
 #define IWL_FLUSH_WAIT_MS      2000
@@ -1511,8 +1461,12 @@ static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt)
        if (time_after(jiffies, timeout)) {
                IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
                        hw_params(trans).wd_timeout);
-               IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n",
+               IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
                        q->read_ptr, q->write_ptr);
+               IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
+                       iwl_read_prph(bus(trans), SCD_QUEUE_RDPTR(cnt))
+                               & (TFD_QUEUE_SIZE_MAX - 1),
+                       iwl_read_prph(bus(trans), SCD_QUEUE_WRPTR(cnt)));
                return 1;
        }
 
@@ -1966,13 +1920,12 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
 #endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 const struct iwl_trans_ops trans_ops_pcie = {
-       .alloc = iwl_trans_pcie_alloc,
        .request_irq = iwl_trans_pcie_request_irq,
+       .fw_alive = iwl_trans_pcie_fw_alive,
        .start_device = iwl_trans_pcie_start_device,
        .prepare_card_hw = iwl_trans_pcie_prepare_card_hw,
        .stop_device = iwl_trans_pcie_stop_device,
 
-       .tx_start = iwl_trans_pcie_tx_start,
        .wake_any_queue = iwl_trans_pcie_wake_any_queue,
 
        .send_cmd = iwl_trans_pcie_send_cmd,
@@ -1998,4 +1951,115 @@ const struct iwl_trans_ops trans_ops_pcie = {
        .suspend = iwl_trans_pcie_suspend,
        .resume = iwl_trans_pcie_resume,
 #endif
+       .write8 = iwl_trans_pcie_write8,
+       .write32 = iwl_trans_pcie_write32,
+       .read32 = iwl_trans_pcie_read32,
 };
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT  0x041
+
+struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd,
+                                      struct pci_dev *pdev,
+                                      const struct pci_device_id *ent)
+{
+       struct iwl_trans_pcie *trans_pcie;
+       struct iwl_trans *trans;
+       u16 pci_cmd;
+       int err;
+
+       trans = kzalloc(sizeof(struct iwl_trans) +
+                            sizeof(struct iwl_trans_pcie), GFP_KERNEL);
+
+       if (WARN_ON(!trans))
+               return NULL;
+
+       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans->ops = &trans_ops_pcie;
+       trans->shrd = shrd;
+       trans_pcie->trans = trans;
+       spin_lock_init(&trans->hcmd_lock);
+
+       /* W/A - seems to solve weird behavior. We need to remove this if we
+        * don't want to stay in L1 all the time. This wastes a lot of power */
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                               PCIE_LINK_STATE_CLKPM);
+
+       if (pci_enable_device(pdev)) {
+               err = -ENODEV;
+               goto out_no_pci;
+       }
+
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (!err)
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (err) {
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (!err)
+                       err = pci_set_consistent_dma_mask(pdev,
+                                                       DMA_BIT_MASK(32));
+               /* both attempts failed: */
+               if (err) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "No suitable DMA available.\n");
+                       goto out_pci_disable_device;
+               }
+       }
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err) {
+               dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed");
+               goto out_pci_disable_device;
+       }
+
+       trans_pcie->hw_base = pci_iomap(pdev, 0, 0);
+       if (!trans_pcie->hw_base) {
+               dev_printk(KERN_ERR, &pdev->dev, "pci_iomap failed");
+               err = -ENODEV;
+               goto out_pci_release_regions;
+       }
+
+       dev_printk(KERN_INFO, &pdev->dev,
+               "pci_resource_len = 0x%08llx\n",
+               (unsigned long long) pci_resource_len(pdev, 0));
+       dev_printk(KERN_INFO, &pdev->dev,
+               "pci_resource_base = %p\n", trans_pcie->hw_base);
+
+       dev_printk(KERN_INFO, &pdev->dev,
+               "HW Revision ID = 0x%X\n", pdev->revision);
+
+       /* We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state */
+       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
+       err = pci_enable_msi(pdev);
+       if (err)
+               dev_printk(KERN_ERR, &pdev->dev,
+                       "pci_enable_msi failed(0X%x)", err);
+
+       trans->dev = &pdev->dev;
+       trans->irq = pdev->irq;
+       trans_pcie->pci_dev = pdev;
+
+       /* TODO: Move this away, not needed if not MSI */
+       /* enable rfkill interrupt: hw bug w/a */
+       pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+       if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+               pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+               pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+       }
+
+       return trans;
+
+out_pci_release_regions:
+       pci_release_regions(pdev);
+out_pci_disable_device:
+       pci_disable_device(pdev);
+out_no_pci:
+       kfree(trans);
+       return NULL;
+}
+
This page took 0.031517 seconds and 5 git commands to generate.