diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2011-08-26 02:11:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-29 15:30:31 -0400 |
commit | ae2c30bfcd29c6f1215d58a1c5663d58978011b8 (patch) | |
tree | 6f21ee56e23c2311100f54f49774a3442aa2e088 /drivers/net | |
parent | fd656935cd05f522d7db97386633f6a0d7751218 (diff) |
iwlagn: stop the device before freeing it
When we remove the module, we free all the tx and rx resources.
Before doing that, we'd better stop the tx / rx activity. Calling
iwl_trans_stop_device in iwl_remove helps also to remove a few API
functions:
* rx_free: happens in iwl_trans_free
* tx_free: happens in iwl_trans_free
* disable_sync_irq: happens in iwl_trans_stop_device
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.c | 42 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 23 |
3 files changed, 22 insertions, 54 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 65a6db5e9a2d..e19ff11c8dc8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -3443,20 +3443,13 @@ void __devexit iwl_remove(struct iwl_priv * priv) | |||
3443 | priv->mac80211_registered = 0; | 3443 | priv->mac80211_registered = 0; |
3444 | } | 3444 | } |
3445 | 3445 | ||
3446 | /* Reset to low power before unloading driver. */ | ||
3447 | iwl_apm_stop(priv); | ||
3448 | |||
3449 | iwl_tt_exit(priv); | 3446 | iwl_tt_exit(priv); |
3450 | 3447 | ||
3451 | /* make sure we flush any pending irq or | 3448 | /*This will stop the queues, move the device to low power state */ |
3452 | * tasklet for the driver */ | 3449 | iwl_trans_stop_device(trans(priv)); |
3453 | iwl_trans_disable_sync_irq(trans(priv)); | ||
3454 | 3450 | ||
3455 | iwl_dealloc_ucode(priv); | 3451 | iwl_dealloc_ucode(priv); |
3456 | 3452 | ||
3457 | iwl_trans_rx_free(trans(priv)); | ||
3458 | iwl_trans_tx_free(trans(priv)); | ||
3459 | |||
3460 | iwl_eeprom_free(priv); | 3453 | iwl_eeprom_free(priv); |
3461 | 3454 | ||
3462 | /*netif_stop_queue(dev); */ | 3455 | /*netif_stop_queue(dev); */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index ac401b805c69..0a3dd6bfd26a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c | |||
@@ -555,7 +555,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans) | |||
555 | return 0; | 555 | return 0; |
556 | 556 | ||
557 | error: | 557 | error: |
558 | iwl_trans_tx_free(trans); | 558 | iwl_trans_pcie_tx_free(trans); |
559 | 559 | ||
560 | return ret; | 560 | return ret; |
561 | } | 561 | } |
@@ -603,7 +603,7 @@ static int iwl_tx_init(struct iwl_trans *trans) | |||
603 | error: | 603 | error: |
604 | /*Upon error, free only if we allocated something */ | 604 | /*Upon error, free only if we allocated something */ |
605 | if (alloc) | 605 | if (alloc) |
606 | iwl_trans_tx_free(trans); | 606 | iwl_trans_pcie_tx_free(trans); |
607 | return ret; | 607 | return ret; |
608 | } | 608 | } |
609 | 609 | ||
@@ -958,13 +958,28 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) | |||
958 | return 0; | 958 | return 0; |
959 | } | 959 | } |
960 | 960 | ||
961 | static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) | ||
962 | { | ||
963 | unsigned long flags; | ||
964 | struct iwl_trans_pcie *trans_pcie = | ||
965 | IWL_TRANS_GET_PCIE_TRANS(trans); | ||
966 | |||
967 | spin_lock_irqsave(&trans->shrd->lock, flags); | ||
968 | iwl_disable_interrupts(trans); | ||
969 | spin_unlock_irqrestore(&trans->shrd->lock, flags); | ||
970 | |||
971 | /* wait to make sure we flush pending tasklet*/ | ||
972 | synchronize_irq(bus(trans)->irq); | ||
973 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
974 | } | ||
975 | |||
961 | static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | 976 | static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) |
962 | { | 977 | { |
963 | /* stop and reset the on-board processor */ | 978 | /* stop and reset the on-board processor */ |
964 | iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | 979 | iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); |
965 | 980 | ||
966 | /* tell the device to stop sending interrupts */ | 981 | /* tell the device to stop sending interrupts */ |
967 | iwl_trans_disable_sync_irq(trans); | 982 | iwl_trans_pcie_disable_sync_irq(trans); |
968 | 983 | ||
969 | /* device going down, Stop using ICT table */ | 984 | /* device going down, Stop using ICT table */ |
970 | iwl_disable_ict(trans); | 985 | iwl_disable_ict(trans); |
@@ -1208,23 +1223,10 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, | |||
1208 | } | 1223 | } |
1209 | } | 1224 | } |
1210 | 1225 | ||
1211 | static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) | ||
1212 | { | ||
1213 | unsigned long flags; | ||
1214 | struct iwl_trans_pcie *trans_pcie = | ||
1215 | IWL_TRANS_GET_PCIE_TRANS(trans); | ||
1216 | |||
1217 | spin_lock_irqsave(&trans->shrd->lock, flags); | ||
1218 | iwl_disable_interrupts(trans); | ||
1219 | spin_unlock_irqrestore(&trans->shrd->lock, flags); | ||
1220 | |||
1221 | /* wait to make sure we flush pending tasklet*/ | ||
1222 | synchronize_irq(bus(trans)->irq); | ||
1223 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
1224 | } | ||
1225 | |||
1226 | static void iwl_trans_pcie_free(struct iwl_trans *trans) | 1226 | static void iwl_trans_pcie_free(struct iwl_trans *trans) |
1227 | { | 1227 | { |
1228 | iwl_trans_pcie_tx_free(trans); | ||
1229 | iwl_trans_pcie_rx_free(trans); | ||
1228 | free_irq(bus(trans)->irq, trans); | 1230 | free_irq(bus(trans)->irq, trans); |
1229 | iwl_free_isr_ict(trans); | 1231 | iwl_free_isr_ict(trans); |
1230 | trans->shrd->trans = NULL; | 1232 | trans->shrd->trans = NULL; |
@@ -1860,9 +1862,6 @@ const struct iwl_trans_ops trans_ops_pcie = { | |||
1860 | 1862 | ||
1861 | .tx_start = iwl_trans_pcie_tx_start, | 1863 | .tx_start = iwl_trans_pcie_tx_start, |
1862 | 1864 | ||
1863 | .rx_free = iwl_trans_pcie_rx_free, | ||
1864 | .tx_free = iwl_trans_pcie_tx_free, | ||
1865 | |||
1866 | .send_cmd = iwl_trans_pcie_send_cmd, | 1865 | .send_cmd = iwl_trans_pcie_send_cmd, |
1867 | .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu, | 1866 | .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu, |
1868 | 1867 | ||
@@ -1875,7 +1874,6 @@ const struct iwl_trans_ops trans_ops_pcie = { | |||
1875 | 1874 | ||
1876 | .kick_nic = iwl_trans_pcie_kick_nic, | 1875 | .kick_nic = iwl_trans_pcie_kick_nic, |
1877 | 1876 | ||
1878 | .disable_sync_irq = iwl_trans_pcie_disable_sync_irq, | ||
1879 | .free = iwl_trans_pcie_free, | 1877 | .free = iwl_trans_pcie_free, |
1880 | 1878 | ||
1881 | .dbgfs_register = iwl_trans_pcie_dbgfs_register, | 1879 | .dbgfs_register = iwl_trans_pcie_dbgfs_register, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0da6ad593f05..e72e4809a410 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -88,8 +88,6 @@ struct iwl_shared; | |||
88 | * @tx_start: starts and configures all the Tx fifo - usually done once the fw | 88 | * @tx_start: starts and configures all the Tx fifo - usually done once the fw |
89 | * is alive. | 89 | * is alive. |
90 | * @stop_device:stops the whole device (embedded CPU put to reset) | 90 | * @stop_device:stops the whole device (embedded CPU put to reset) |
91 | * @rx_free: frees the rx memory | ||
92 | * @tx_free: frees the tx memory | ||
93 | * @send_cmd:send a host command | 91 | * @send_cmd:send a host command |
94 | * @send_cmd_pdu:send a host command: flags can be CMD_* | 92 | * @send_cmd_pdu:send a host command: flags can be CMD_* |
95 | * @get_tx_cmd: returns a pointer to a new Tx cmd for the upper layer use | 93 | * @get_tx_cmd: returns a pointer to a new Tx cmd for the upper layer use |
@@ -99,9 +97,6 @@ struct iwl_shared; | |||
99 | * ready and a successful ADDBA response has been received. | 97 | * ready and a successful ADDBA response has been received. |
100 | * @txq_agg_disable: de-configure a Tx queue to send AMPDUs | 98 | * @txq_agg_disable: de-configure a Tx queue to send AMPDUs |
101 | * @kick_nic: remove the RESET from the embedded CPU and let it run | 99 | * @kick_nic: remove the RESET from the embedded CPU and let it run |
102 | * @disable_sync_irq: Disable and sync: after this handler returns, it is | ||
103 | * guaranteed that all the ISR / tasklet etc... have finished running | ||
104 | * and the transport layer shall not pass any Rx. | ||
105 | * @free: release all the ressource for the transport layer itself such as | 100 | * @free: release all the ressource for the transport layer itself such as |
106 | * irq, tasklet etc... | 101 | * irq, tasklet etc... |
107 | * @dbgfs_register: add the dbgfs files under this directory. Files will be | 102 | * @dbgfs_register: add the dbgfs files under this directory. Files will be |
@@ -117,8 +112,6 @@ struct iwl_trans_ops { | |||
117 | int (*prepare_card_hw)(struct iwl_trans *trans); | 112 | int (*prepare_card_hw)(struct iwl_trans *trans); |
118 | void (*stop_device)(struct iwl_trans *trans); | 113 | void (*stop_device)(struct iwl_trans *trans); |
119 | void (*tx_start)(struct iwl_trans *trans); | 114 | void (*tx_start)(struct iwl_trans *trans); |
120 | void (*tx_free)(struct iwl_trans *trans); | ||
121 | void (*rx_free)(struct iwl_trans *trans); | ||
122 | 115 | ||
123 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); | 116 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); |
124 | 117 | ||
@@ -138,7 +131,6 @@ struct iwl_trans_ops { | |||
138 | 131 | ||
139 | void (*kick_nic)(struct iwl_trans *trans); | 132 | void (*kick_nic)(struct iwl_trans *trans); |
140 | 133 | ||
141 | void (*disable_sync_irq)(struct iwl_trans *trans); | ||
142 | void (*free)(struct iwl_trans *trans); | 134 | void (*free)(struct iwl_trans *trans); |
143 | 135 | ||
144 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); | 136 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); |
@@ -187,16 +179,6 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans) | |||
187 | trans->ops->tx_start(trans); | 179 | trans->ops->tx_start(trans); |
188 | } | 180 | } |
189 | 181 | ||
190 | static inline void iwl_trans_rx_free(struct iwl_trans *trans) | ||
191 | { | ||
192 | trans->ops->rx_free(trans); | ||
193 | } | ||
194 | |||
195 | static inline void iwl_trans_tx_free(struct iwl_trans *trans) | ||
196 | { | ||
197 | trans->ops->tx_free(trans); | ||
198 | } | ||
199 | |||
200 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 182 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
201 | struct iwl_host_cmd *cmd) | 183 | struct iwl_host_cmd *cmd) |
202 | { | 184 | { |
@@ -247,11 +229,6 @@ static inline void iwl_trans_kick_nic(struct iwl_trans *trans) | |||
247 | trans->ops->kick_nic(trans); | 229 | trans->ops->kick_nic(trans); |
248 | } | 230 | } |
249 | 231 | ||
250 | static inline void iwl_trans_disable_sync_irq(struct iwl_trans *trans) | ||
251 | { | ||
252 | trans->ops->disable_sync_irq(trans); | ||
253 | } | ||
254 | |||
255 | static inline void iwl_trans_free(struct iwl_trans *trans) | 232 | static inline void iwl_trans_free(struct iwl_trans *trans) |
256 | { | 233 | { |
257 | trans->ops->free(trans); | 234 | trans->ops->free(trans); |