summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2012-02-02 14:33:08 -0800
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2012-02-02 14:34:48 -0800
commita42a184458ae95937893cb873c988385637c5e14 (patch)
tree70638d63f2383c63485c5a58b03a31a89dfba085 /drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
parentb52e7ea109cfe4ea7fea99b1cd20f57ccd95476a (diff)
downloadlinux-a42a184458ae95937893cb873c988385637c5e14.tar.bz2
iwlwifi: move the bus configuration to transport
All the bus configuration is now done in the transport allocation fucntion. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans-pcie.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c169
1 files changed, 141 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index f0d8cccbcb11..5d0cfe033407 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -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>
@@ -1042,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 */
@@ -1246,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;
}
@@ -1299,13 +1301,22 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
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);
#endif
- free_irq(bus(trans)->irq, trans);
+ 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);
}
@@ -1374,30 +1385,6 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
}
}
-const struct iwl_trans_ops trans_ops_pcie;
-
-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 *iwl_trans = kzalloc(sizeof(struct iwl_trans) +
- sizeof(struct iwl_trans_pcie),
- GFP_KERNEL);
-
- if (WARN_ON(!iwl_trans))
- return NULL;
-
- 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,
const char *msg)
{
@@ -1949,3 +1936,129 @@ const struct iwl_trans_ops trans_ops_pcie = {
.resume = iwl_trans_pcie_resume,
#endif
};
+
+/* TODO: remove this hack - will be possible when all the io{write/read} ops
+ * will be done through the transport
+ */
+struct iwl_pci_bus {
+ /* basic pci-network driver stuff */
+ struct pci_dev *pci_dev;
+
+ /* pci hardware address support */
+ void __iomem *hw_base;
+};
+
+#define IWL_BUS_GET_PCI_BUS(_iwl_bus) \
+ ((struct iwl_pci_bus *) ((_iwl_bus)->bus_specific))
+
+/* 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_pci_bus *iwl_pci_bus = IWL_BUS_GET_PCI_BUS(shrd->bus);
+ 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;
+ }
+
+ /* TODO: remove this hack */
+ iwl_pci_bus->hw_base = trans_pcie->hw_base;
+
+ 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;
+}
+