diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/pci.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 136 |
1 files changed, 89 insertions, 47 deletions
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b5b651413e77..3bad0b2cf9a3 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2011 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/nl80211.h> | 17 | #include <linux/nl80211.h> |
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/ath9k_platform.h> | ||
19 | #include "ath9k.h" | 20 | #include "ath9k.h" |
20 | 21 | ||
21 | static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { | 22 | static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { |
@@ -29,6 +30,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { | |||
29 | { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ | 30 | { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ |
30 | { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ | 31 | { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ |
31 | { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ | 32 | { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ |
33 | { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ | ||
32 | { 0 } | 34 | { 0 } |
33 | }; | 35 | }; |
34 | 36 | ||
@@ -42,7 +44,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) | |||
42 | *csz = (int)u8tmp; | 44 | *csz = (int)u8tmp; |
43 | 45 | ||
44 | /* | 46 | /* |
45 | * This check was put in to avoid "unplesant" consequences if | 47 | * This check was put in to avoid "unpleasant" consequences if |
46 | * the bootrom has not fully initialized all PCI devices. | 48 | * the bootrom has not fully initialized all PCI devices. |
47 | * Sometimes the cache line size register is not set | 49 | * Sometimes the cache line size register is not set |
48 | */ | 50 | */ |
@@ -53,21 +55,35 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) | |||
53 | 55 | ||
54 | static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) | 56 | static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) |
55 | { | 57 | { |
56 | struct ath_hw *ah = (struct ath_hw *) common->ah; | 58 | struct ath_softc *sc = (struct ath_softc *) common->priv; |
57 | 59 | struct ath9k_platform_data *pdata = sc->dev->platform_data; | |
58 | common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); | 60 | |
59 | 61 | if (pdata) { | |
60 | if (!ath9k_hw_wait(ah, | 62 | if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { |
61 | AR_EEPROM_STATUS_DATA, | 63 | ath_err(common, |
62 | AR_EEPROM_STATUS_DATA_BUSY | | 64 | "%s: eeprom read failed, offset %08x is out of range\n", |
63 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, | 65 | __func__, off); |
64 | AH_WAIT_TIMEOUT)) { | 66 | } |
65 | return false; | 67 | |
68 | *data = pdata->eeprom_data[off]; | ||
69 | } else { | ||
70 | struct ath_hw *ah = (struct ath_hw *) common->ah; | ||
71 | |||
72 | common->ops->read(ah, AR5416_EEPROM_OFFSET + | ||
73 | (off << AR5416_EEPROM_S)); | ||
74 | |||
75 | if (!ath9k_hw_wait(ah, | ||
76 | AR_EEPROM_STATUS_DATA, | ||
77 | AR_EEPROM_STATUS_DATA_BUSY | | ||
78 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, | ||
79 | AH_WAIT_TIMEOUT)) { | ||
80 | return false; | ||
81 | } | ||
82 | |||
83 | *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), | ||
84 | AR_EEPROM_STATUS_DATA_VAL); | ||
66 | } | 85 | } |
67 | 86 | ||
68 | *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), | ||
69 | AR_EEPROM_STATUS_DATA_VAL); | ||
70 | |||
71 | return true; | 87 | return true; |
72 | } | 88 | } |
73 | 89 | ||
@@ -80,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) | |||
80 | struct pci_dev *pdev = to_pci_dev(sc->dev); | 96 | struct pci_dev *pdev = to_pci_dev(sc->dev); |
81 | u8 aspm; | 97 | u8 aspm; |
82 | 98 | ||
83 | if (!pdev->is_pcie) | 99 | if (!pci_is_pcie(pdev)) |
84 | return; | 100 | return; |
85 | 101 | ||
86 | pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); | 102 | pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); |
@@ -88,17 +104,28 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) | |||
88 | pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); | 104 | pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); |
89 | } | 105 | } |
90 | 106 | ||
107 | static void ath_pci_extn_synch_enable(struct ath_common *common) | ||
108 | { | ||
109 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
110 | struct pci_dev *pdev = to_pci_dev(sc->dev); | ||
111 | u8 lnkctl; | ||
112 | |||
113 | pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl); | ||
114 | lnkctl |= PCI_EXP_LNKCTL_ES; | ||
115 | pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); | ||
116 | } | ||
117 | |||
91 | static const struct ath_bus_ops ath_pci_bus_ops = { | 118 | static const struct ath_bus_ops ath_pci_bus_ops = { |
92 | .ath_bus_type = ATH_PCI, | 119 | .ath_bus_type = ATH_PCI, |
93 | .read_cachesize = ath_pci_read_cachesize, | 120 | .read_cachesize = ath_pci_read_cachesize, |
94 | .eeprom_read = ath_pci_eeprom_read, | 121 | .eeprom_read = ath_pci_eeprom_read, |
95 | .bt_coex_prep = ath_pci_bt_coex_prep, | 122 | .bt_coex_prep = ath_pci_bt_coex_prep, |
123 | .extn_synch_en = ath_pci_extn_synch_enable, | ||
96 | }; | 124 | }; |
97 | 125 | ||
98 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 126 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
99 | { | 127 | { |
100 | void __iomem *mem; | 128 | void __iomem *mem; |
101 | struct ath_wiphy *aphy; | ||
102 | struct ath_softc *sc; | 129 | struct ath_softc *sc; |
103 | struct ieee80211_hw *hw; | 130 | struct ieee80211_hw *hw; |
104 | u8 csz; | 131 | u8 csz; |
@@ -170,8 +197,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
170 | goto err_iomap; | 197 | goto err_iomap; |
171 | } | 198 | } |
172 | 199 | ||
173 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + | 200 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); |
174 | sizeof(struct ath_softc), &ath9k_ops); | ||
175 | if (!hw) { | 201 | if (!hw) { |
176 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); | 202 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); |
177 | ret = -ENOMEM; | 203 | ret = -ENOMEM; |
@@ -181,11 +207,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
181 | SET_IEEE80211_DEV(hw, &pdev->dev); | 207 | SET_IEEE80211_DEV(hw, &pdev->dev); |
182 | pci_set_drvdata(pdev, hw); | 208 | pci_set_drvdata(pdev, hw); |
183 | 209 | ||
184 | aphy = hw->priv; | 210 | sc = hw->priv; |
185 | sc = (struct ath_softc *) (aphy + 1); | ||
186 | aphy->sc = sc; | ||
187 | aphy->hw = hw; | ||
188 | sc->pri_wiphy = aphy; | ||
189 | sc->hw = hw; | 211 | sc->hw = hw; |
190 | sc->dev = &pdev->dev; | 212 | sc->dev = &pdev->dev; |
191 | sc->mem = mem; | 213 | sc->mem = mem; |
@@ -232,10 +254,11 @@ err_dma: | |||
232 | static void ath_pci_remove(struct pci_dev *pdev) | 254 | static void ath_pci_remove(struct pci_dev *pdev) |
233 | { | 255 | { |
234 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 256 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
235 | struct ath_wiphy *aphy = hw->priv; | 257 | struct ath_softc *sc = hw->priv; |
236 | struct ath_softc *sc = aphy->sc; | ||
237 | void __iomem *mem = sc->mem; | 258 | void __iomem *mem = sc->mem; |
238 | 259 | ||
260 | if (!is_ath9k_unloaded) | ||
261 | sc->sc_ah->ah_flags |= AH_UNPLUGGED; | ||
239 | ath9k_deinit_device(sc); | 262 | ath9k_deinit_device(sc); |
240 | free_irq(sc->irq, sc); | 263 | free_irq(sc->irq, sc); |
241 | ieee80211_free_hw(sc->hw); | 264 | ieee80211_free_hw(sc->hw); |
@@ -247,34 +270,29 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
247 | 270 | ||
248 | #ifdef CONFIG_PM | 271 | #ifdef CONFIG_PM |
249 | 272 | ||
250 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 273 | static int ath_pci_suspend(struct device *device) |
251 | { | 274 | { |
275 | struct pci_dev *pdev = to_pci_dev(device); | ||
252 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 276 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
253 | struct ath_wiphy *aphy = hw->priv; | 277 | struct ath_softc *sc = hw->priv; |
254 | struct ath_softc *sc = aphy->sc; | ||
255 | 278 | ||
256 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 279 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
257 | 280 | ||
258 | pci_save_state(pdev); | 281 | /* The device has to be moved to FULLSLEEP forcibly. |
259 | pci_disable_device(pdev); | 282 | * Otherwise the chip never moved to full sleep, |
260 | pci_set_power_state(pdev, PCI_D3hot); | 283 | * when no interface is up. |
284 | */ | ||
285 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); | ||
261 | 286 | ||
262 | return 0; | 287 | return 0; |
263 | } | 288 | } |
264 | 289 | ||
265 | static int ath_pci_resume(struct pci_dev *pdev) | 290 | static int ath_pci_resume(struct device *device) |
266 | { | 291 | { |
292 | struct pci_dev *pdev = to_pci_dev(device); | ||
267 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 293 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
268 | struct ath_wiphy *aphy = hw->priv; | 294 | struct ath_softc *sc = hw->priv; |
269 | struct ath_softc *sc = aphy->sc; | ||
270 | u32 val; | 295 | u32 val; |
271 | int err; | ||
272 | |||
273 | pci_restore_state(pdev); | ||
274 | |||
275 | err = pci_enable_device(pdev); | ||
276 | if (err) | ||
277 | return err; | ||
278 | 296 | ||
279 | /* | 297 | /* |
280 | * Suspend/Resume resets the PCI configuration space, so we have to | 298 | * Suspend/Resume resets the PCI configuration space, so we have to |
@@ -290,10 +308,37 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
290 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 308 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
291 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 309 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
292 | 310 | ||
311 | /* | ||
312 | * Reset key cache to sane defaults (all entries cleared) instead of | ||
313 | * semi-random values after suspend/resume. | ||
314 | */ | ||
315 | ath9k_ps_wakeup(sc); | ||
316 | ath9k_init_crypto(sc); | ||
317 | ath9k_ps_restore(sc); | ||
318 | |||
319 | sc->ps_idle = true; | ||
320 | ath_radio_disable(sc, hw); | ||
321 | |||
293 | return 0; | 322 | return 0; |
294 | } | 323 | } |
295 | 324 | ||
296 | #endif /* CONFIG_PM */ | 325 | static const struct dev_pm_ops ath9k_pm_ops = { |
326 | .suspend = ath_pci_suspend, | ||
327 | .resume = ath_pci_resume, | ||
328 | .freeze = ath_pci_suspend, | ||
329 | .thaw = ath_pci_resume, | ||
330 | .poweroff = ath_pci_suspend, | ||
331 | .restore = ath_pci_resume, | ||
332 | }; | ||
333 | |||
334 | #define ATH9K_PM_OPS (&ath9k_pm_ops) | ||
335 | |||
336 | #else /* !CONFIG_PM */ | ||
337 | |||
338 | #define ATH9K_PM_OPS NULL | ||
339 | |||
340 | #endif /* !CONFIG_PM */ | ||
341 | |||
297 | 342 | ||
298 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); | 343 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); |
299 | 344 | ||
@@ -302,10 +347,7 @@ static struct pci_driver ath_pci_driver = { | |||
302 | .id_table = ath_pci_id_table, | 347 | .id_table = ath_pci_id_table, |
303 | .probe = ath_pci_probe, | 348 | .probe = ath_pci_probe, |
304 | .remove = ath_pci_remove, | 349 | .remove = ath_pci_remove, |
305 | #ifdef CONFIG_PM | 350 | .driver.pm = ATH9K_PM_OPS, |
306 | .suspend = ath_pci_suspend, | ||
307 | .resume = ath_pci_resume, | ||
308 | #endif /* CONFIG_PM */ | ||
309 | }; | 351 | }; |
310 | 352 | ||
311 | int ath_pci_init(void) | 353 | int ath_pci_init(void) |