aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/iwl-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-pci.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-pci.c229
1 files changed, 34 insertions, 195 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
index 03702a2e913..3e2fce4ce00 100644
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
@@ -71,112 +71,6 @@
#include "iwl-csr.h"
#include "iwl-cfg.h"
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT 0x041
-#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01
-#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02
-
-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))
-
-#define IWL_BUS_GET_PCI_DEV(_iwl_bus) \
- ((IWL_BUS_GET_PCI_BUS(_iwl_bus))->pci_dev)
-
-static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus)
-{
- int pos;
- u16 pci_lnk_ctl;
-
- struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
-
- pos = pci_pcie_cap(pci_dev);
- pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
- return pci_lnk_ctl;
-}
-
-static bool iwl_pci_is_pm_supported(struct iwl_bus *bus)
-{
- u16 lctl = iwl_pciexp_link_ctrl(bus);
-
- return !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
-}
-
-static void iwl_pci_apm_config(struct iwl_bus *bus)
-{
- /*
- * HW bug W/A for instability in PCIe bus L0S->L1 transition.
- * Check if BIOS (or OS) enabled L1-ASPM on this device.
- * If so (likely), disable L0S, so device moves directly L0->L1;
- * costs negligible amount of power savings.
- * If not (unlikely), enable L0S, so there is at least some
- * power savings, even without L1.
- */
- u16 lctl = iwl_pciexp_link_ctrl(bus);
-
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
- PCI_CFG_LINK_CTRL_VAL_L1_EN) {
- /* L1-ASPM enabled; disable(!) L0S */
- iwl_set_bit(bus, CSR_GIO_REG,
- CSR_GIO_REG_VAL_L0S_ENABLED);
- dev_printk(KERN_INFO, bus->dev, "L1 Enabled; Disabling L0S\n");
- } else {
- /* L1-ASPM disabled; enable(!) L0S */
- iwl_clear_bit(bus, CSR_GIO_REG,
- CSR_GIO_REG_VAL_L0S_ENABLED);
- dev_printk(KERN_INFO, bus->dev, "L1 Disabled; Enabling L0S\n");
- }
-}
-
-static void iwl_pci_get_hw_id_string(struct iwl_bus *bus, char buf[],
- int buf_len)
-{
- struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
-
- snprintf(buf, buf_len, "PCI ID: 0x%04X:0x%04X", pci_dev->device,
- pci_dev->subsystem_device);
-}
-
-static u32 iwl_pci_get_hw_id(struct iwl_bus *bus)
-{
- struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
-
- return (pci_dev->device << 16) + pci_dev->subsystem_device;
-}
-
-static void iwl_pci_write8(struct iwl_bus *bus, u32 ofs, u8 val)
-{
- iowrite8(val, IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs);
-}
-
-static void iwl_pci_write32(struct iwl_bus *bus, u32 ofs, u32 val)
-{
- iowrite32(val, IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs);
-}
-
-static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs)
-{
- u32 val = ioread32(IWL_BUS_GET_PCI_BUS(bus)->hw_base + ofs);
- return val;
-}
-
-static const struct iwl_bus_ops bus_ops_pci = {
- .get_pm_support = iwl_pci_is_pm_supported,
- .apm_config = iwl_pci_apm_config,
- .get_hw_id_string = iwl_pci_get_hw_id_string,
- .get_hw_id = iwl_pci_get_hw_id,
- .write8 = iwl_pci_write8,
- .write32 = iwl_pci_write32,
- .read32 = iwl_pci_read32,
-};
-
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
@@ -362,112 +256,61 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
};
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT 0x041
+
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
struct iwl_bus *bus;
- struct iwl_pci_bus *pci_bus;
- u16 pci_cmd;
int err;
- bus = kzalloc(sizeof(*bus) + sizeof(*pci_bus), GFP_KERNEL);
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus) {
dev_printk(KERN_ERR, &pdev->dev,
"Couldn't allocate iwl_pci_bus");
- err = -ENOMEM;
- goto out_no_pci;
+ return -ENOMEM;
}
- pci_bus = IWL_BUS_GET_PCI_BUS(bus);
- pci_bus->pci_dev = pdev;
-
- pci_set_drvdata(pdev, bus);
-
- /* 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;
+ bus->shrd = kzalloc(sizeof(*bus->shrd), GFP_KERNEL);
+ if (!bus->shrd) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "Couldn't allocate iwl_shared");
+ err = -ENOMEM;
+ goto out_free_bus;
}
- 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, bus->dev,
- "No suitable DMA available.\n");
- goto out_pci_disable_device;
- }
- }
+ bus->shrd->bus = bus;
- err = pci_request_regions(pdev, DRV_NAME);
- if (err) {
- dev_printk(KERN_ERR, bus->dev, "pci_request_regions failed");
- goto out_pci_disable_device;
- }
+ pci_set_drvdata(pdev, bus);
- pci_bus->hw_base = pci_iomap(pdev, 0, 0);
- if (!pci_bus->hw_base) {
- dev_printk(KERN_ERR, bus->dev, "pci_iomap failed");
- err = -ENODEV;
- goto out_pci_release_regions;
+#ifdef CONFIG_IWLWIFI_IDI
+ trans(bus) = iwl_trans_idi_alloc(bus->shrd, pdev, ent);
+ if (trans(bus) == NULL) {
+ err = -ENOMEM;
+ goto out_free_bus;
}
- 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", pci_bus->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);
-
- /* 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);
+ err = iwl_probe(bus, &trans_ops_idi, cfg);
+#else
+ trans(bus) = iwl_trans_pcie_alloc(bus->shrd, pdev, ent);
+ if (trans(bus) == NULL) {
+ err = -ENOMEM;
+ goto out_free_bus;
}
- bus->dev = &pdev->dev;
- bus->irq = pdev->irq;
- bus->ops = &bus_ops_pci;
-
err = iwl_probe(bus, &trans_ops_pcie, cfg);
+#endif
if (err)
- goto out_disable_msi;
+ goto out_free_trans;
+
return 0;
-out_disable_msi:
- pci_disable_msi(pdev);
- pci_iounmap(pdev, pci_bus->hw_base);
-out_pci_release_regions:
+out_free_trans:
+ iwl_trans_free(trans(bus));
pci_set_drvdata(pdev, NULL);
- pci_release_regions(pdev);
-out_pci_disable_device:
- pci_disable_device(pdev);
-out_no_pci:
+out_free_bus:
+ kfree(bus->shrd);
kfree(bus);
return err;
}
@@ -475,18 +318,14 @@ out_no_pci:
static void __devexit iwl_pci_remove(struct pci_dev *pdev)
{
struct iwl_bus *bus = pci_get_drvdata(pdev);
- struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus);
- struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
struct iwl_shared *shrd = bus->shrd;
iwl_remove(shrd->priv);
+ iwl_trans_free(shrd->trans);
- pci_disable_msi(pci_dev);
- pci_iounmap(pci_dev, pci_bus->hw_base);
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
- pci_set_drvdata(pci_dev, NULL);
+ pci_set_drvdata(pdev, NULL);
+ kfree(bus->shrd);
kfree(bus);
}