]> Pileus Git - ~andy/linux/blobdiff - drivers/net/wireless/ath/ath9k/pci.c
ath9k: Fix warnings on card removal
[~andy/linux] / drivers / net / wireless / ath / ath9k / pci.c
index b5b651413e77104bdd4bffe3171354287ed0a828..3eb938d7a012bb695270ad16b929dcb0112914a3 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/nl80211.h>
 #include <linux/pci.h>
+#include <linux/ath9k_platform.h>
 #include "ath9k.h"
 
 static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
@@ -29,6 +30,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
        { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
+       { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
        { 0 }
 };
 
@@ -53,21 +55,35 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
 
 static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 {
-       struct ath_hw *ah = (struct ath_hw *) common->ah;
-
-       common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
-       if (!ath9k_hw_wait(ah,
-                          AR_EEPROM_STATUS_DATA,
-                          AR_EEPROM_STATUS_DATA_BUSY |
-                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
-                          AH_WAIT_TIMEOUT)) {
-               return false;
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+       struct ath9k_platform_data *pdata = sc->dev->platform_data;
+
+       if (pdata) {
+               if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
+                       ath_err(common,
+                               "%s: eeprom read failed, offset %08x is out of range\n",
+                               __func__, off);
+               }
+
+               *data = pdata->eeprom_data[off];
+       } else {
+               struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+               common->ops->read(ah, AR5416_EEPROM_OFFSET +
+                                     (off << AR5416_EEPROM_S));
+
+               if (!ath9k_hw_wait(ah,
+                                  AR_EEPROM_STATUS_DATA,
+                                  AR_EEPROM_STATUS_DATA_BUSY |
+                                  AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+                                  AH_WAIT_TIMEOUT)) {
+                       return false;
+               }
+
+               *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
+                          AR_EEPROM_STATUS_DATA_VAL);
        }
 
-       *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
-                  AR_EEPROM_STATUS_DATA_VAL);
-
        return true;
 }
 
@@ -88,11 +104,23 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
        pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
 }
 
+static void ath_pci_extn_synch_enable(struct ath_common *common)
+{
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+       struct pci_dev *pdev = to_pci_dev(sc->dev);
+       u8 lnkctl;
+
+       pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl);
+       lnkctl |= PCI_EXP_LNKCTL_ES;
+       pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
+}
+
 static const struct ath_bus_ops ath_pci_bus_ops = {
        .ath_bus_type = ATH_PCI,
        .read_cachesize = ath_pci_read_cachesize,
        .eeprom_read = ath_pci_eeprom_read,
        .bt_coex_prep = ath_pci_bt_coex_prep,
+       .extn_synch_en = ath_pci_extn_synch_enable,
 };
 
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -236,6 +264,8 @@ static void ath_pci_remove(struct pci_dev *pdev)
        struct ath_softc *sc = aphy->sc;
        void __iomem *mem = sc->mem;
 
+       if (!is_ath9k_unloaded)
+               sc->sc_ah->ah_flags |= AH_UNPLUGGED;
        ath9k_deinit_device(sc);
        free_irq(sc->irq, sc);
        ieee80211_free_hw(sc->hw);
@@ -247,34 +277,25 @@ static void ath_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
-static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ath_pci_suspend(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
 
        ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-
        return 0;
 }
 
-static int ath_pci_resume(struct pci_dev *pdev)
+static int ath_pci_resume(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        u32 val;
-       int err;
-
-       pci_restore_state(pdev);
-
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
 
        /*
         * Suspend/Resume resets the PCI configuration space, so we have to
@@ -290,10 +311,29 @@ static int ath_pci_resume(struct pci_dev *pdev)
                            AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
        ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
+       sc->ps_idle = true;
+       ath_radio_disable(sc, hw);
+
        return 0;
 }
 
-#endif /* CONFIG_PM */
+static const struct dev_pm_ops ath9k_pm_ops = {
+       .suspend = ath_pci_suspend,
+       .resume = ath_pci_resume,
+       .freeze = ath_pci_suspend,
+       .thaw = ath_pci_resume,
+       .poweroff = ath_pci_suspend,
+       .restore = ath_pci_resume,
+};
+
+#define ATH9K_PM_OPS   (&ath9k_pm_ops)
+
+#else /* !CONFIG_PM */
+
+#define ATH9K_PM_OPS   NULL
+
+#endif /* !CONFIG_PM */
+
 
 MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
 
@@ -302,10 +342,7 @@ static struct pci_driver ath_pci_driver = {
        .id_table   = ath_pci_id_table,
        .probe      = ath_pci_probe,
        .remove     = ath_pci_remove,
-#ifdef CONFIG_PM
-       .suspend    = ath_pci_suspend,
-       .resume     = ath_pci_resume,
-#endif /* CONFIG_PM */
+       .driver.pm  = ATH9K_PM_OPS,
 };
 
 int ath_pci_init(void)