]>
Commit | Line | Data |
---|---|---|
eda50cde SS |
1 | /****************************************************************************** |
2 | * | |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | * redistributing this file, you may do so under either license. | |
5 | * | |
6 | * GPL LICENSE SUMMARY | |
7 | * | |
8 | * Copyright(c) 2017 Intel Deutschland GmbH | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of version 2 of the GNU General Public License as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * BSD LICENSE | |
20 | * | |
21 | * Copyright(c) 2017 Intel Deutschland GmbH | |
22 | * All rights reserved. | |
23 | * | |
24 | * Redistribution and use in source and binary forms, with or without | |
25 | * modification, are permitted provided that the following conditions | |
26 | * are met: | |
27 | * | |
28 | * * Redistributions of source code must retain the above copyright | |
29 | * notice, this list of conditions and the following disclaimer. | |
30 | * * Redistributions in binary form must reproduce the above copyright | |
31 | * notice, this list of conditions and the following disclaimer in | |
32 | * the documentation and/or other materials provided with the | |
33 | * distribution. | |
34 | * * Neither the name Intel Corporation nor the names of its | |
35 | * contributors may be used to endorse or promote products derived | |
36 | * from this software without specific prior written permission. | |
37 | * | |
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
39 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
40 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
41 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
42 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
44 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
45 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
46 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
47 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
48 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
49 | * | |
50 | *****************************************************************************/ | |
51 | #include "iwl-trans.h" | |
0232d2cd | 52 | #include "iwl-prph.h" |
eda50cde SS |
53 | #include "iwl-context-info.h" |
54 | #include "internal.h" | |
55 | ||
56 | /* | |
57 | * Start up NIC's basic functionality after it has been reset | |
58 | * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop()) | |
59 | * NOTE: This does not load uCode nor start the embedded processor | |
60 | */ | |
61 | static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) | |
62 | { | |
63 | int ret = 0; | |
64 | ||
65 | IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); | |
66 | ||
67 | /* | |
68 | * Use "set_bit" below rather than "write", to preserve any hardware | |
69 | * bits already set by default after reset. | |
70 | */ | |
71 | ||
72 | /* | |
73 | * Disable L0s without affecting L1; | |
74 | * don't wait for ICH L0s (ICH bug W/A) | |
75 | */ | |
76 | iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, | |
77 | CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); | |
78 | ||
79 | /* Set FH wait threshold to maximum (HW error during stress W/A) */ | |
80 | iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); | |
81 | ||
82 | /* | |
83 | * Enable HAP INTA (interrupt from management bus) to | |
84 | * wake device's PCI Express link L1a -> L0s | |
85 | */ | |
86 | iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | |
87 | CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); | |
88 | ||
89 | iwl_pcie_apm_config(trans); | |
90 | ||
91 | /* | |
92 | * Set "initialization complete" bit to move adapter from | |
93 | * D0U* --> D0A* (powered-up active) state. | |
94 | */ | |
95 | iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | |
96 | ||
97 | /* | |
98 | * Wait for clock stabilization; once stabilized, access to | |
99 | * device-internal resources is supported, e.g. iwl_write_prph() | |
100 | * and accesses to uCode SRAM. | |
101 | */ | |
102 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | |
103 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | |
104 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); | |
105 | if (ret < 0) { | |
106 | IWL_DEBUG_INFO(trans, "Failed to init the card\n"); | |
107 | return ret; | |
108 | } | |
109 | ||
110 | set_bit(STATUS_DEVICE_ENABLED, &trans->status); | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
77c09bc8 SS |
115 | static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) |
116 | { | |
117 | IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); | |
118 | ||
119 | if (op_mode_leave) { | |
120 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) | |
121 | iwl_pcie_gen2_apm_init(trans); | |
122 | ||
123 | /* inform ME that we are leaving */ | |
124 | iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, | |
125 | CSR_RESET_LINK_PWR_MGMT_DISABLED); | |
126 | iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | |
127 | CSR_HW_IF_CONFIG_REG_PREPARE | | |
128 | CSR_HW_IF_CONFIG_REG_ENABLE_PME); | |
129 | mdelay(1); | |
130 | iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, | |
131 | CSR_RESET_LINK_PWR_MGMT_DISABLED); | |
132 | mdelay(5); | |
133 | } | |
134 | ||
135 | clear_bit(STATUS_DEVICE_ENABLED, &trans->status); | |
136 | ||
137 | /* Stop device's DMA activity */ | |
138 | iwl_pcie_apm_stop_master(trans); | |
139 | ||
099a628b | 140 | iwl_pcie_sw_reset(trans); |
77c09bc8 SS |
141 | |
142 | /* | |
143 | * Clear "initialization complete" bit to move adapter from | |
144 | * D0A* (powered-up Active) --> D0U* (Uninitialized) state. | |
145 | */ | |
146 | iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | |
147 | } | |
148 | ||
149 | void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) | |
150 | { | |
151 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
77c09bc8 SS |
152 | |
153 | lockdep_assert_held(&trans_pcie->mutex); | |
154 | ||
155 | if (trans_pcie->is_down) | |
156 | return; | |
157 | ||
158 | trans_pcie->is_down = true; | |
159 | ||
0232d2cd SS |
160 | /* Stop dbgc before stopping device */ |
161 | iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); | |
162 | udelay(100); | |
163 | iwl_write_prph(trans, DBGC_OUT_CTRL, 0); | |
164 | ||
77c09bc8 SS |
165 | /* tell the device to stop sending interrupts */ |
166 | iwl_disable_interrupts(trans); | |
167 | ||
168 | /* device going down, Stop using ICT table */ | |
169 | iwl_pcie_disable_ict(trans); | |
170 | ||
171 | /* | |
172 | * If a HW restart happens during firmware loading, | |
173 | * then the firmware loading might call this function | |
174 | * and later it might be called again due to the | |
175 | * restart. So don't process again if the device is | |
176 | * already dead. | |
177 | */ | |
178 | if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { | |
179 | IWL_DEBUG_INFO(trans, | |
180 | "DEVICE_ENABLED bit was set and is now cleared\n"); | |
13a3a390 | 181 | iwl_pcie_gen2_tx_stop(trans); |
77c09bc8 SS |
182 | iwl_pcie_rx_stop(trans); |
183 | } | |
184 | ||
185 | iwl_pcie_ctxt_info_free_paging(trans); | |
186 | iwl_pcie_ctxt_info_free(trans); | |
187 | ||
188 | /* Make sure (redundant) we've released our request to stay awake */ | |
189 | iwl_clear_bit(trans, CSR_GP_CNTRL, | |
190 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | |
191 | ||
192 | /* Stop the device, and put it in low power state */ | |
193 | iwl_pcie_gen2_apm_stop(trans, false); | |
194 | ||
099a628b | 195 | iwl_pcie_sw_reset(trans); |
77c09bc8 SS |
196 | |
197 | /* | |
198 | * Upon stop, the IVAR table gets erased, so msi-x won't | |
199 | * work. This causes a bug in RF-KILL flows, since the interrupt | |
200 | * that enables radio won't fire on the correct irq, and the | |
201 | * driver won't be able to handle the interrupt. | |
202 | * Configure the IVAR table again after reset. | |
203 | */ | |
204 | iwl_pcie_conf_msix_hw(trans_pcie); | |
205 | ||
206 | /* | |
207 | * Upon stop, the APM issues an interrupt if HW RF kill is set. | |
208 | * This is a bug in certain verions of the hardware. | |
209 | * Certain devices also keep sending HW RF kill interrupt all | |
210 | * the time, unless the interrupt is ACKed even if the interrupt | |
211 | * should be masked. Re-ACK all the interrupts here. | |
212 | */ | |
213 | iwl_disable_interrupts(trans); | |
214 | ||
215 | /* clear all status bits */ | |
216 | clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); | |
217 | clear_bit(STATUS_INT_ENABLED, &trans->status); | |
218 | clear_bit(STATUS_TPOWER_PMI, &trans->status); | |
77c09bc8 SS |
219 | |
220 | /* | |
221 | * Even if we stop the HW, we still want the RF kill | |
222 | * interrupt | |
223 | */ | |
224 | iwl_enable_rfkill_int(trans); | |
225 | ||
77c09bc8 SS |
226 | /* re-take ownership to prevent other users from stealing the device */ |
227 | iwl_pcie_prepare_card_hw(trans); | |
228 | } | |
229 | ||
230 | void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) | |
231 | { | |
232 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
326477e4 | 233 | bool was_in_rfkill; |
77c09bc8 SS |
234 | |
235 | mutex_lock(&trans_pcie->mutex); | |
326477e4 JB |
236 | trans_pcie->opmode_down = true; |
237 | was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); | |
77c09bc8 | 238 | _iwl_trans_pcie_gen2_stop_device(trans, low_power); |
326477e4 | 239 | iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); |
77c09bc8 SS |
240 | mutex_unlock(&trans_pcie->mutex); |
241 | } | |
242 | ||
eda50cde SS |
243 | static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) |
244 | { | |
245 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
246 | ||
247 | /* TODO: most of the logic can be removed in A0 - but not in Z0 */ | |
248 | spin_lock(&trans_pcie->irq_lock); | |
249 | iwl_pcie_gen2_apm_init(trans); | |
250 | spin_unlock(&trans_pcie->irq_lock); | |
251 | ||
252 | iwl_op_mode_nic_config(trans->op_mode); | |
253 | ||
254 | /* Allocate the RX queue, or reset if it is already allocated */ | |
255 | if (iwl_pcie_gen2_rx_init(trans)) | |
256 | return -ENOMEM; | |
257 | ||
258 | /* Allocate or reset and init all Tx and Command queues */ | |
259 | if (iwl_pcie_gen2_tx_init(trans)) | |
260 | return -ENOMEM; | |
261 | ||
262 | /* enable shadow regs in HW */ | |
263 | iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); | |
264 | IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n"); | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) | |
270 | { | |
271 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
272 | ||
273 | iwl_pcie_reset_ict(trans); | |
274 | ||
275 | /* make sure all queue are not stopped/used */ | |
276 | memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); | |
277 | memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); | |
278 | ||
279 | /* now that we got alive we can free the fw image & the context info. | |
280 | * paging memory cannot be freed included since FW will still use it | |
281 | */ | |
282 | iwl_pcie_ctxt_info_free(trans); | |
283 | } | |
284 | ||
285 | int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, | |
286 | const struct fw_img *fw, bool run_in_rfkill) | |
287 | { | |
288 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | |
289 | bool hw_rfkill; | |
290 | int ret; | |
291 | ||
292 | /* This may fail if AMT took ownership of the device */ | |
293 | if (iwl_pcie_prepare_card_hw(trans)) { | |
294 | IWL_WARN(trans, "Exit HW not ready\n"); | |
295 | ret = -EIO; | |
296 | goto out; | |
297 | } | |
298 | ||
299 | iwl_enable_rfkill_int(trans); | |
300 | ||
301 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); | |
302 | ||
303 | /* | |
304 | * We enabled the RF-Kill interrupt and the handler may very | |
305 | * well be running. Disable the interrupts to make sure no other | |
306 | * interrupt can be fired. | |
307 | */ | |
308 | iwl_disable_interrupts(trans); | |
309 | ||
310 | /* Make sure it finished running */ | |
311 | iwl_pcie_synchronize_irqs(trans); | |
312 | ||
313 | mutex_lock(&trans_pcie->mutex); | |
314 | ||
315 | /* If platform's RF_KILL switch is NOT set to KILL */ | |
9ad8fd0b | 316 | hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); |
eda50cde SS |
317 | if (hw_rfkill && !run_in_rfkill) { |
318 | ret = -ERFKILL; | |
319 | goto out; | |
320 | } | |
321 | ||
322 | /* Someone called stop_device, don't try to start_fw */ | |
323 | if (trans_pcie->is_down) { | |
324 | IWL_WARN(trans, | |
325 | "Can't start_fw since the HW hasn't been started\n"); | |
326 | ret = -EIO; | |
327 | goto out; | |
328 | } | |
329 | ||
330 | /* make sure rfkill handshake bits are cleared */ | |
331 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | |
332 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, | |
333 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | |
334 | ||
335 | /* clear (again), then enable host interrupts */ | |
336 | iwl_write32(trans, CSR_INT, 0xFFFFFFFF); | |
337 | ||
338 | ret = iwl_pcie_gen2_nic_init(trans); | |
339 | if (ret) { | |
340 | IWL_ERR(trans, "Unable to init nic\n"); | |
341 | goto out; | |
342 | } | |
343 | ||
97b00d87 JB |
344 | ret = iwl_pcie_ctxt_info_init(trans, fw); |
345 | if (ret) | |
346 | goto out; | |
eda50cde SS |
347 | |
348 | /* re-check RF-Kill state since we may have missed the interrupt */ | |
9ad8fd0b | 349 | hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); |
eda50cde SS |
350 | if (hw_rfkill && !run_in_rfkill) |
351 | ret = -ERFKILL; | |
352 | ||
353 | out: | |
354 | mutex_unlock(&trans_pcie->mutex); | |
355 | return ret; | |
356 | } |