1 | // SPDX-License-Identifier: BSD-3-Clause-Clear |
2 | /* |
3 | * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/module.h> |
8 | #include <linux/msi.h> |
9 | #include <linux/pci.h> |
10 | #include <linux/of.h> |
11 | |
12 | #include "pci.h" |
13 | #include "core.h" |
14 | #include "hif.h" |
15 | #include "mhi.h" |
16 | #include "debug.h" |
17 | #include "pcic.h" |
18 | #include "qmi.h" |
19 | |
20 | #define ATH11K_PCI_BAR_NUM 0 |
21 | #define ATH11K_PCI_DMA_MASK 36 |
22 | #define ATH11K_PCI_COHERENT_DMA_MASK 32 |
23 | |
24 | #define TCSR_SOC_HW_VERSION 0x0224 |
25 | #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) |
26 | #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) |
27 | |
28 | #define QCA6390_DEVICE_ID 0x1101 |
29 | #define QCN9074_DEVICE_ID 0x1104 |
30 | #define WCN6855_DEVICE_ID 0x1103 |
31 | |
32 | #define TCSR_SOC_HW_SUB_VER 0x1910010 |
33 | |
34 | static const struct pci_device_id ath11k_pci_id_table[] = { |
35 | { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, |
36 | { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, |
37 | { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, |
38 | {0} |
39 | }; |
40 | |
41 | MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); |
42 | |
43 | static int ath11k_pci_bus_wake_up(struct ath11k_base *ab) |
44 | { |
45 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
46 | |
47 | return mhi_device_get_sync(mhi_dev: ab_pci->mhi_ctrl->mhi_dev); |
48 | } |
49 | |
50 | static void ath11k_pci_bus_release(struct ath11k_base *ab) |
51 | { |
52 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
53 | |
54 | mhi_device_put(mhi_dev: ab_pci->mhi_ctrl->mhi_dev); |
55 | } |
56 | |
57 | static u32 ath11k_pci_get_window_start(struct ath11k_base *ab, u32 offset) |
58 | { |
59 | if (!ab->hw_params.static_window_map) |
60 | return ATH11K_PCI_WINDOW_START; |
61 | |
62 | if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK) |
63 | /* if offset lies within DP register range, use 3rd window */ |
64 | return 3 * ATH11K_PCI_WINDOW_START; |
65 | else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) < |
66 | ATH11K_PCI_WINDOW_RANGE_MASK) |
67 | /* if offset lies within CE register range, use 2nd window */ |
68 | return 2 * ATH11K_PCI_WINDOW_START; |
69 | else |
70 | return ATH11K_PCI_WINDOW_START; |
71 | } |
72 | |
73 | static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) |
74 | { |
75 | struct ath11k_base *ab = ab_pci->ab; |
76 | |
77 | u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); |
78 | |
79 | lockdep_assert_held(&ab_pci->window_lock); |
80 | |
81 | if (window != ab_pci->register_window) { |
82 | iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, |
83 | ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); |
84 | ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); |
85 | ab_pci->register_window = window; |
86 | } |
87 | } |
88 | |
89 | static void |
90 | ath11k_pci_window_write32(struct ath11k_base *ab, u32 offset, u32 value) |
91 | { |
92 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
93 | u32 window_start; |
94 | |
95 | window_start = ath11k_pci_get_window_start(ab, offset); |
96 | |
97 | if (window_start == ATH11K_PCI_WINDOW_START) { |
98 | spin_lock_bh(lock: &ab_pci->window_lock); |
99 | ath11k_pci_select_window(ab_pci, offset); |
100 | iowrite32(value, ab->mem + window_start + |
101 | (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); |
102 | spin_unlock_bh(lock: &ab_pci->window_lock); |
103 | } else { |
104 | iowrite32(value, ab->mem + window_start + |
105 | (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); |
106 | } |
107 | } |
108 | |
109 | static u32 ath11k_pci_window_read32(struct ath11k_base *ab, u32 offset) |
110 | { |
111 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
112 | u32 window_start, val; |
113 | |
114 | window_start = ath11k_pci_get_window_start(ab, offset); |
115 | |
116 | if (window_start == ATH11K_PCI_WINDOW_START) { |
117 | spin_lock_bh(lock: &ab_pci->window_lock); |
118 | ath11k_pci_select_window(ab_pci, offset); |
119 | val = ioread32(ab->mem + window_start + |
120 | (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); |
121 | spin_unlock_bh(lock: &ab_pci->window_lock); |
122 | } else { |
123 | val = ioread32(ab->mem + window_start + |
124 | (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); |
125 | } |
126 | |
127 | return val; |
128 | } |
129 | |
130 | int ath11k_pci_get_msi_irq(struct ath11k_base *ab, unsigned int vector) |
131 | { |
132 | struct pci_dev *pci_dev = to_pci_dev(ab->dev); |
133 | |
134 | return pci_irq_vector(dev: pci_dev, nr: vector); |
135 | } |
136 | |
137 | static const struct ath11k_pci_ops ath11k_pci_ops_qca6390 = { |
138 | .wakeup = ath11k_pci_bus_wake_up, |
139 | .release = ath11k_pci_bus_release, |
140 | .get_msi_irq = ath11k_pci_get_msi_irq, |
141 | .window_write32 = ath11k_pci_window_write32, |
142 | .window_read32 = ath11k_pci_window_read32, |
143 | }; |
144 | |
145 | static const struct ath11k_pci_ops ath11k_pci_ops_qcn9074 = { |
146 | .wakeup = NULL, |
147 | .release = NULL, |
148 | .get_msi_irq = ath11k_pci_get_msi_irq, |
149 | .window_write32 = ath11k_pci_window_write32, |
150 | .window_read32 = ath11k_pci_window_read32, |
151 | }; |
152 | |
153 | static const struct ath11k_msi_config msi_config_one_msi = { |
154 | .total_vectors = 1, |
155 | .total_users = 4, |
156 | .users = (struct ath11k_msi_user[]) { |
157 | { .name = "MHI" , .num_vectors = 3, .base_vector = 0 }, |
158 | { .name = "CE" , .num_vectors = 1, .base_vector = 0 }, |
159 | { .name = "WAKE" , .num_vectors = 1, .base_vector = 0 }, |
160 | { .name = "DP" , .num_vectors = 1, .base_vector = 0 }, |
161 | }, |
162 | }; |
163 | |
164 | static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) |
165 | { |
166 | u32 umac_window; |
167 | u32 ce_window; |
168 | u32 window; |
169 | |
170 | umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); |
171 | ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); |
172 | window = (umac_window << 12) | (ce_window << 6); |
173 | |
174 | iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, |
175 | ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); |
176 | } |
177 | |
178 | static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) |
179 | { |
180 | u32 val, delay; |
181 | |
182 | val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); |
183 | |
184 | val |= PCIE_SOC_GLOBAL_RESET_V; |
185 | |
186 | ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, value: val); |
187 | |
188 | /* TODO: exact time to sleep is uncertain */ |
189 | delay = 10; |
190 | mdelay(delay); |
191 | |
192 | /* Need to toggle V bit back otherwise stuck in reset status */ |
193 | val &= ~PCIE_SOC_GLOBAL_RESET_V; |
194 | |
195 | ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, value: val); |
196 | |
197 | mdelay(delay); |
198 | |
199 | val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); |
200 | if (val == 0xffffffff) |
201 | ath11k_warn(ab, fmt: "link down error during global reset\n" ); |
202 | } |
203 | |
204 | static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) |
205 | { |
206 | u32 val; |
207 | |
208 | /* read cookie */ |
209 | val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR); |
210 | ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_q6_cookie_addr 0x%x\n" , val); |
211 | |
212 | val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); |
213 | ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n" , val); |
214 | |
215 | /* TODO: exact time to sleep is uncertain */ |
216 | mdelay(10); |
217 | |
218 | /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from |
219 | * continuing warm path and entering dead loop. |
220 | */ |
221 | ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, value: 0); |
222 | mdelay(10); |
223 | |
224 | val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); |
225 | ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n" , val); |
226 | |
227 | /* A read clear register. clear the register to prevent |
228 | * Q6 from entering wrong code path. |
229 | */ |
230 | val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG); |
231 | ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause %d\n" , val); |
232 | } |
233 | |
234 | static int ath11k_pci_set_link_reg(struct ath11k_base *ab, |
235 | u32 offset, u32 value, u32 mask) |
236 | { |
237 | u32 v; |
238 | int i; |
239 | |
240 | v = ath11k_pcic_read32(ab, offset); |
241 | if ((v & mask) == value) |
242 | return 0; |
243 | |
244 | for (i = 0; i < 10; i++) { |
245 | ath11k_pcic_write32(ab, offset, value: (v & ~mask) | value); |
246 | |
247 | v = ath11k_pcic_read32(ab, offset); |
248 | if ((v & mask) == value) |
249 | return 0; |
250 | |
251 | mdelay(2); |
252 | } |
253 | |
254 | ath11k_warn(ab, fmt: "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n" , |
255 | offset, v & mask, value); |
256 | |
257 | return -ETIMEDOUT; |
258 | } |
259 | |
260 | static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) |
261 | { |
262 | int ret; |
263 | |
264 | ret = ath11k_pci_set_link_reg(ab, |
265 | PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), |
266 | PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, |
267 | PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); |
268 | if (ret) { |
269 | ath11k_warn(ab, fmt: "failed to set sysclk: %d\n" , ret); |
270 | return ret; |
271 | } |
272 | |
273 | ret = ath11k_pci_set_link_reg(ab, |
274 | PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), |
275 | PCIE_PCS_OSC_DTCT_CONFIG1_VAL, |
276 | PCIE_PCS_OSC_DTCT_CONFIG_MSK); |
277 | if (ret) { |
278 | ath11k_warn(ab, fmt: "failed to set dtct config1 error: %d\n" , ret); |
279 | return ret; |
280 | } |
281 | |
282 | ret = ath11k_pci_set_link_reg(ab, |
283 | PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), |
284 | PCIE_PCS_OSC_DTCT_CONFIG2_VAL, |
285 | PCIE_PCS_OSC_DTCT_CONFIG_MSK); |
286 | if (ret) { |
287 | ath11k_warn(ab, fmt: "failed to set dtct config2: %d\n" , ret); |
288 | return ret; |
289 | } |
290 | |
291 | ret = ath11k_pci_set_link_reg(ab, |
292 | PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), |
293 | PCIE_PCS_OSC_DTCT_CONFIG4_VAL, |
294 | PCIE_PCS_OSC_DTCT_CONFIG_MSK); |
295 | if (ret) { |
296 | ath11k_warn(ab, fmt: "failed to set dtct config4: %d\n" , ret); |
297 | return ret; |
298 | } |
299 | |
300 | return 0; |
301 | } |
302 | |
303 | static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) |
304 | { |
305 | u32 val; |
306 | int i; |
307 | |
308 | val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); |
309 | |
310 | /* PCIE link seems very unstable after the Hot Reset*/ |
311 | for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { |
312 | if (val == 0xffffffff) |
313 | mdelay(5); |
314 | |
315 | ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); |
316 | val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); |
317 | } |
318 | |
319 | ath11k_dbg(ab, ATH11K_DBG_PCI, "ltssm 0x%x\n" , val); |
320 | |
321 | val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); |
322 | val |= GCC_GCC_PCIE_HOT_RST_VAL; |
323 | ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, value: val); |
324 | val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); |
325 | |
326 | ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_hot_rst 0x%x\n" , val); |
327 | |
328 | mdelay(5); |
329 | } |
330 | |
331 | static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) |
332 | { |
333 | /* This is a WAR for PCIE Hotreset. |
334 | * When target receive Hotreset, but will set the interrupt. |
335 | * So when download SBL again, SBL will open Interrupt and |
336 | * receive it, and crash immediately. |
337 | */ |
338 | ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); |
339 | } |
340 | |
341 | static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) |
342 | { |
343 | u32 val; |
344 | |
345 | val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); |
346 | val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; |
347 | ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, value: val); |
348 | } |
349 | |
350 | static void ath11k_pci_force_wake(struct ath11k_base *ab) |
351 | { |
352 | ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, value: 1); |
353 | mdelay(5); |
354 | } |
355 | |
356 | static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) |
357 | { |
358 | mdelay(100); |
359 | |
360 | if (power_on) { |
361 | ath11k_pci_enable_ltssm(ab); |
362 | ath11k_pci_clear_all_intrs(ab); |
363 | ath11k_pci_set_wlaon_pwr_ctrl(ab); |
364 | if (ab->hw_params.fix_l1ss) |
365 | ath11k_pci_fix_l1ss(ab); |
366 | } |
367 | |
368 | ath11k_mhi_clear_vector(ab); |
369 | ath11k_pci_clear_dbg_registers(ab); |
370 | ath11k_pci_soc_global_reset(ab); |
371 | ath11k_mhi_set_mhictrl_reset(ab); |
372 | } |
373 | |
374 | static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) |
375 | { |
376 | struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; |
377 | |
378 | cfg->tgt_ce = ab->hw_params.target_ce_config; |
379 | cfg->tgt_ce_len = ab->hw_params.target_ce_count; |
380 | |
381 | cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; |
382 | cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; |
383 | ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; |
384 | |
385 | ath11k_ce_get_shadow_config(ab, shadow_cfg: &cfg->shadow_reg_v2, |
386 | shadow_cfg_len: &cfg->shadow_reg_v2_len); |
387 | } |
388 | |
389 | static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) |
390 | { |
391 | struct pci_dev *dev = ab_pci->pdev; |
392 | u16 control; |
393 | |
394 | pci_read_config_word(dev, where: dev->msi_cap + PCI_MSI_FLAGS, val: &control); |
395 | |
396 | if (enable) |
397 | control |= PCI_MSI_FLAGS_ENABLE; |
398 | else |
399 | control &= ~PCI_MSI_FLAGS_ENABLE; |
400 | |
401 | pci_write_config_word(dev, where: dev->msi_cap + PCI_MSI_FLAGS, val: control); |
402 | } |
403 | |
404 | static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) |
405 | { |
406 | ath11k_pci_msi_config(ab_pci, enable: true); |
407 | } |
408 | |
409 | static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) |
410 | { |
411 | ath11k_pci_msi_config(ab_pci, enable: false); |
412 | } |
413 | |
414 | static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) |
415 | { |
416 | struct ath11k_base *ab = ab_pci->ab; |
417 | const struct ath11k_msi_config *msi_config = ab->pci.msi.config; |
418 | struct pci_dev *pci_dev = ab_pci->pdev; |
419 | struct msi_desc *msi_desc; |
420 | int num_vectors; |
421 | int ret; |
422 | |
423 | num_vectors = pci_alloc_irq_vectors(dev: pci_dev, |
424 | min_vecs: msi_config->total_vectors, |
425 | max_vecs: msi_config->total_vectors, |
426 | PCI_IRQ_MSI); |
427 | if (num_vectors == msi_config->total_vectors) { |
428 | set_bit(nr: ATH11K_FLAG_MULTI_MSI_VECTORS, addr: &ab->dev_flags); |
429 | } else { |
430 | num_vectors = pci_alloc_irq_vectors(dev: ab_pci->pdev, |
431 | min_vecs: 1, |
432 | max_vecs: 1, |
433 | PCI_IRQ_MSI); |
434 | if (num_vectors < 0) { |
435 | ret = -EINVAL; |
436 | goto reset_msi_config; |
437 | } |
438 | clear_bit(nr: ATH11K_FLAG_MULTI_MSI_VECTORS, addr: &ab->dev_flags); |
439 | ab->pci.msi.config = &msi_config_one_msi; |
440 | ath11k_dbg(ab, ATH11K_DBG_PCI, "request one msi vector\n" ); |
441 | } |
442 | ath11k_info(ab, fmt: "MSI vectors: %d\n" , num_vectors); |
443 | |
444 | ath11k_pci_msi_disable(ab_pci); |
445 | |
446 | msi_desc = irq_get_msi_desc(irq: ab_pci->pdev->irq); |
447 | if (!msi_desc) { |
448 | ath11k_err(ab, fmt: "msi_desc is NULL!\n" ); |
449 | ret = -EINVAL; |
450 | goto free_msi_vector; |
451 | } |
452 | |
453 | ab->pci.msi.ep_base_data = msi_desc->msg.data; |
454 | |
455 | pci_read_config_dword(dev: pci_dev, where: pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, |
456 | val: &ab->pci.msi.addr_lo); |
457 | |
458 | if (msi_desc->pci.msi_attrib.is_64) { |
459 | pci_read_config_dword(dev: pci_dev, where: pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, |
460 | val: &ab->pci.msi.addr_hi); |
461 | } else { |
462 | ab->pci.msi.addr_hi = 0; |
463 | } |
464 | |
465 | ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n" , ab->pci.msi.ep_base_data); |
466 | |
467 | return 0; |
468 | |
469 | free_msi_vector: |
470 | pci_free_irq_vectors(dev: ab_pci->pdev); |
471 | |
472 | reset_msi_config: |
473 | return ret; |
474 | } |
475 | |
476 | static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) |
477 | { |
478 | pci_free_irq_vectors(dev: ab_pci->pdev); |
479 | } |
480 | |
481 | static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) |
482 | { |
483 | struct msi_desc *msi_desc; |
484 | |
485 | msi_desc = irq_get_msi_desc(irq: ab_pci->pdev->irq); |
486 | if (!msi_desc) { |
487 | ath11k_err(ab: ab_pci->ab, fmt: "msi_desc is NULL!\n" ); |
488 | pci_free_irq_vectors(dev: ab_pci->pdev); |
489 | return -EINVAL; |
490 | } |
491 | |
492 | ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data; |
493 | |
494 | ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "after request_irq msi_ep_base_data %d\n" , |
495 | ab_pci->ab->pci.msi.ep_base_data); |
496 | |
497 | return 0; |
498 | } |
499 | |
500 | static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) |
501 | { |
502 | struct ath11k_base *ab = ab_pci->ab; |
503 | u16 device_id; |
504 | int ret = 0; |
505 | |
506 | pci_read_config_word(dev: pdev, PCI_DEVICE_ID, val: &device_id); |
507 | if (device_id != ab_pci->dev_id) { |
508 | ath11k_err(ab, fmt: "pci device id mismatch: 0x%x 0x%x\n" , |
509 | device_id, ab_pci->dev_id); |
510 | ret = -EIO; |
511 | goto out; |
512 | } |
513 | |
514 | ret = pci_assign_resource(dev: pdev, ATH11K_PCI_BAR_NUM); |
515 | if (ret) { |
516 | ath11k_err(ab, fmt: "failed to assign pci resource: %d\n" , ret); |
517 | goto out; |
518 | } |
519 | |
520 | ret = pci_enable_device(dev: pdev); |
521 | if (ret) { |
522 | ath11k_err(ab, fmt: "failed to enable pci device: %d\n" , ret); |
523 | goto out; |
524 | } |
525 | |
526 | ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci" ); |
527 | if (ret) { |
528 | ath11k_err(ab, fmt: "failed to request pci region: %d\n" , ret); |
529 | goto disable_device; |
530 | } |
531 | |
532 | ret = dma_set_mask(dev: &pdev->dev, |
533 | DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); |
534 | if (ret) { |
535 | ath11k_err(ab, fmt: "failed to set pci dma mask to %d: %d\n" , |
536 | ATH11K_PCI_DMA_MASK, ret); |
537 | goto release_region; |
538 | } |
539 | |
540 | ab_pci->dma_mask = DMA_BIT_MASK(ATH11K_PCI_DMA_MASK); |
541 | |
542 | ret = dma_set_coherent_mask(dev: &pdev->dev, |
543 | DMA_BIT_MASK(ATH11K_PCI_COHERENT_DMA_MASK)); |
544 | if (ret) { |
545 | ath11k_err(ab, fmt: "failed to set pci coherent dma mask to %d: %d\n" , |
546 | ATH11K_PCI_COHERENT_DMA_MASK, ret); |
547 | goto release_region; |
548 | } |
549 | |
550 | pci_set_master(dev: pdev); |
551 | |
552 | ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); |
553 | ab->mem = pci_iomap(dev: pdev, ATH11K_PCI_BAR_NUM, max: 0); |
554 | if (!ab->mem) { |
555 | ath11k_err(ab, fmt: "failed to map pci bar %d\n" , ATH11K_PCI_BAR_NUM); |
556 | ret = -EIO; |
557 | goto release_region; |
558 | } |
559 | |
560 | ab->mem_ce = ab->mem; |
561 | |
562 | ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci_mem 0x%p\n" , ab->mem); |
563 | return 0; |
564 | |
565 | release_region: |
566 | pci_release_region(pdev, ATH11K_PCI_BAR_NUM); |
567 | disable_device: |
568 | pci_disable_device(dev: pdev); |
569 | out: |
570 | return ret; |
571 | } |
572 | |
573 | static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) |
574 | { |
575 | struct ath11k_base *ab = ab_pci->ab; |
576 | struct pci_dev *pci_dev = ab_pci->pdev; |
577 | |
578 | pci_iounmap(dev: pci_dev, ab->mem); |
579 | ab->mem = NULL; |
580 | pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); |
581 | if (pci_is_enabled(pdev: pci_dev)) |
582 | pci_disable_device(dev: pci_dev); |
583 | } |
584 | |
585 | static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) |
586 | { |
587 | struct ath11k_base *ab = ab_pci->ab; |
588 | |
589 | pcie_capability_read_word(dev: ab_pci->pdev, PCI_EXP_LNKCTL, |
590 | val: &ab_pci->link_ctl); |
591 | |
592 | ath11k_dbg(ab, ATH11K_DBG_PCI, "link_ctl 0x%04x L0s %d L1 %d\n" , |
593 | ab_pci->link_ctl, |
594 | u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), |
595 | u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); |
596 | |
597 | /* disable L0s and L1 */ |
598 | pcie_capability_clear_word(dev: ab_pci->pdev, PCI_EXP_LNKCTL, |
599 | PCI_EXP_LNKCTL_ASPMC); |
600 | |
601 | set_bit(nr: ATH11K_PCI_ASPM_RESTORE, addr: &ab_pci->flags); |
602 | } |
603 | |
604 | static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) |
605 | { |
606 | if (test_and_clear_bit(nr: ATH11K_PCI_ASPM_RESTORE, addr: &ab_pci->flags)) |
607 | pcie_capability_clear_and_set_word(dev: ab_pci->pdev, PCI_EXP_LNKCTL, |
608 | PCI_EXP_LNKCTL_ASPMC, |
609 | set: ab_pci->link_ctl & |
610 | PCI_EXP_LNKCTL_ASPMC); |
611 | } |
612 | |
613 | static int ath11k_pci_power_up(struct ath11k_base *ab) |
614 | { |
615 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
616 | int ret; |
617 | |
618 | ab_pci->register_window = 0; |
619 | clear_bit(nr: ATH11K_FLAG_DEVICE_INIT_DONE, addr: &ab->dev_flags); |
620 | ath11k_pci_sw_reset(ab: ab_pci->ab, power_on: true); |
621 | |
622 | /* Disable ASPM during firmware download due to problems switching |
623 | * to AMSS state. |
624 | */ |
625 | ath11k_pci_aspm_disable(ab_pci); |
626 | |
627 | ath11k_pci_msi_enable(ab_pci); |
628 | |
629 | ret = ath11k_mhi_start(ar_pci: ab_pci); |
630 | if (ret) { |
631 | ath11k_err(ab, fmt: "failed to start mhi: %d\n" , ret); |
632 | return ret; |
633 | } |
634 | |
635 | if (ab->hw_params.static_window_map) |
636 | ath11k_pci_select_static_window(ab_pci); |
637 | |
638 | return 0; |
639 | } |
640 | |
641 | static void ath11k_pci_power_down(struct ath11k_base *ab) |
642 | { |
643 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
644 | |
645 | /* restore aspm in case firmware bootup fails */ |
646 | ath11k_pci_aspm_restore(ab_pci); |
647 | |
648 | ath11k_pci_force_wake(ab: ab_pci->ab); |
649 | |
650 | ath11k_pci_msi_disable(ab_pci); |
651 | |
652 | ath11k_mhi_stop(ar_pci: ab_pci); |
653 | clear_bit(nr: ATH11K_FLAG_DEVICE_INIT_DONE, addr: &ab->dev_flags); |
654 | ath11k_pci_sw_reset(ab: ab_pci->ab, power_on: false); |
655 | } |
656 | |
657 | static int ath11k_pci_hif_suspend(struct ath11k_base *ab) |
658 | { |
659 | struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); |
660 | |
661 | return ath11k_mhi_suspend(ar_pci); |
662 | } |
663 | |
664 | static int ath11k_pci_hif_resume(struct ath11k_base *ab) |
665 | { |
666 | struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); |
667 | |
668 | return ath11k_mhi_resume(ar_pci); |
669 | } |
670 | |
671 | static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) |
672 | { |
673 | ath11k_pcic_ce_irqs_enable(ab); |
674 | } |
675 | |
676 | static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) |
677 | { |
678 | ath11k_pcic_ce_irq_disable_sync(ab); |
679 | } |
680 | |
681 | static int ath11k_pci_start(struct ath11k_base *ab) |
682 | { |
683 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
684 | |
685 | /* TODO: for now don't restore ASPM in case of single MSI |
686 | * vector as MHI register reading in M2 causes system hang. |
687 | */ |
688 | if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) |
689 | ath11k_pci_aspm_restore(ab_pci); |
690 | else |
691 | ath11k_info(ab, fmt: "leaving PCI ASPM disabled to avoid MHI M2 problems\n" ); |
692 | |
693 | ath11k_pcic_start(ab); |
694 | |
695 | return 0; |
696 | } |
697 | |
698 | static const struct ath11k_hif_ops ath11k_pci_hif_ops = { |
699 | .start = ath11k_pci_start, |
700 | .stop = ath11k_pcic_stop, |
701 | .read32 = ath11k_pcic_read32, |
702 | .write32 = ath11k_pcic_write32, |
703 | .read = ath11k_pcic_read, |
704 | .power_down = ath11k_pci_power_down, |
705 | .power_up = ath11k_pci_power_up, |
706 | .suspend = ath11k_pci_hif_suspend, |
707 | .resume = ath11k_pci_hif_resume, |
708 | .irq_enable = ath11k_pcic_ext_irq_enable, |
709 | .irq_disable = ath11k_pcic_ext_irq_disable, |
710 | .get_msi_address = ath11k_pcic_get_msi_address, |
711 | .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment, |
712 | .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, |
713 | .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, |
714 | .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, |
715 | .get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx, |
716 | }; |
717 | |
718 | static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) |
719 | { |
720 | u32 soc_hw_version; |
721 | |
722 | soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION); |
723 | *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, |
724 | soc_hw_version); |
725 | *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, |
726 | soc_hw_version); |
727 | |
728 | ath11k_dbg(ab, ATH11K_DBG_PCI, "tcsr_soc_hw_version major %d minor %d\n" , |
729 | *major, *minor); |
730 | } |
731 | |
732 | static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, |
733 | const struct cpumask *m) |
734 | { |
735 | if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags)) |
736 | return 0; |
737 | |
738 | return irq_set_affinity_hint(irq: ab_pci->pdev->irq, m); |
739 | } |
740 | |
741 | static int ath11k_pci_probe(struct pci_dev *pdev, |
742 | const struct pci_device_id *pci_dev) |
743 | { |
744 | struct ath11k_base *ab; |
745 | struct ath11k_pci *ab_pci; |
746 | u32 soc_hw_version_major, soc_hw_version_minor, addr; |
747 | int ret; |
748 | u32 sub_version; |
749 | |
750 | ab = ath11k_core_alloc(dev: &pdev->dev, priv_size: sizeof(*ab_pci), bus: ATH11K_BUS_PCI); |
751 | |
752 | if (!ab) { |
753 | dev_err(&pdev->dev, "failed to allocate ath11k base\n" ); |
754 | return -ENOMEM; |
755 | } |
756 | |
757 | ab->dev = &pdev->dev; |
758 | pci_set_drvdata(pdev, data: ab); |
759 | ab_pci = ath11k_pci_priv(ab); |
760 | ab_pci->dev_id = pci_dev->device; |
761 | ab_pci->ab = ab; |
762 | ab_pci->pdev = pdev; |
763 | ab->hif.ops = &ath11k_pci_hif_ops; |
764 | ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL; |
765 | pci_set_drvdata(pdev, data: ab); |
766 | spin_lock_init(&ab_pci->window_lock); |
767 | |
768 | /* Set fixed_mem_region to true for platforms support reserved memory |
769 | * from DT. If memory is reserved from DT for FW, ath11k driver need not |
770 | * allocate memory. |
771 | */ |
772 | ret = of_property_read_u32(np: ab->dev->of_node, propname: "memory-region" , out_value: &addr); |
773 | if (!ret) |
774 | set_bit(nr: ATH11K_FLAG_FIXED_MEM_RGN, addr: &ab->dev_flags); |
775 | |
776 | ret = ath11k_pci_claim(ab_pci, pdev); |
777 | if (ret) { |
778 | ath11k_err(ab, fmt: "failed to claim device: %d\n" , ret); |
779 | goto err_free_core; |
780 | } |
781 | |
782 | ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n" , |
783 | pdev->vendor, pdev->device, |
784 | pdev->subsystem_vendor, pdev->subsystem_device); |
785 | |
786 | ab->id.vendor = pdev->vendor; |
787 | ab->id.device = pdev->device; |
788 | ab->id.subsystem_vendor = pdev->subsystem_vendor; |
789 | ab->id.subsystem_device = pdev->subsystem_device; |
790 | |
791 | switch (pci_dev->device) { |
792 | case QCA6390_DEVICE_ID: |
793 | ret = ath11k_pcic_register_pci_ops(ab, pci_ops: &ath11k_pci_ops_qca6390); |
794 | if (ret) { |
795 | ath11k_err(ab, fmt: "failed to register PCI ops: %d\n" , ret); |
796 | goto err_pci_free_region; |
797 | } |
798 | |
799 | ath11k_pci_read_hw_version(ab, major: &soc_hw_version_major, |
800 | minor: &soc_hw_version_minor); |
801 | switch (soc_hw_version_major) { |
802 | case 2: |
803 | ab->hw_rev = ATH11K_HW_QCA6390_HW20; |
804 | break; |
805 | default: |
806 | dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n" , |
807 | soc_hw_version_major, soc_hw_version_minor); |
808 | ret = -EOPNOTSUPP; |
809 | goto err_pci_free_region; |
810 | } |
811 | |
812 | break; |
813 | case QCN9074_DEVICE_ID: |
814 | ret = ath11k_pcic_register_pci_ops(ab, pci_ops: &ath11k_pci_ops_qcn9074); |
815 | if (ret) { |
816 | ath11k_err(ab, fmt: "failed to register PCI ops: %d\n" , ret); |
817 | goto err_pci_free_region; |
818 | } |
819 | ab->hw_rev = ATH11K_HW_QCN9074_HW10; |
820 | break; |
821 | case WCN6855_DEVICE_ID: |
822 | ret = ath11k_pcic_register_pci_ops(ab, pci_ops: &ath11k_pci_ops_qca6390); |
823 | if (ret) { |
824 | ath11k_err(ab, fmt: "failed to register PCI ops: %d\n" , ret); |
825 | goto err_pci_free_region; |
826 | } |
827 | ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; |
828 | ath11k_pci_read_hw_version(ab, major: &soc_hw_version_major, |
829 | minor: &soc_hw_version_minor); |
830 | switch (soc_hw_version_major) { |
831 | case 2: |
832 | switch (soc_hw_version_minor) { |
833 | case 0x00: |
834 | case 0x01: |
835 | ab->hw_rev = ATH11K_HW_WCN6855_HW20; |
836 | break; |
837 | case 0x10: |
838 | case 0x11: |
839 | sub_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_SUB_VER); |
840 | ath11k_dbg(ab, ATH11K_DBG_PCI, "sub_version 0x%x\n" , |
841 | sub_version); |
842 | switch (sub_version) { |
843 | case 0x1019A0E1: |
844 | case 0x1019B0E1: |
845 | case 0x1019C0E1: |
846 | case 0x1019D0E1: |
847 | ab->hw_rev = ATH11K_HW_QCA2066_HW21; |
848 | break; |
849 | default: |
850 | ab->hw_rev = ATH11K_HW_WCN6855_HW21; |
851 | } |
852 | break; |
853 | default: |
854 | goto unsupported_wcn6855_soc; |
855 | } |
856 | break; |
857 | default: |
858 | unsupported_wcn6855_soc: |
859 | dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n" , |
860 | soc_hw_version_major, soc_hw_version_minor); |
861 | ret = -EOPNOTSUPP; |
862 | goto err_pci_free_region; |
863 | } |
864 | |
865 | break; |
866 | default: |
867 | dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n" , |
868 | pci_dev->device); |
869 | ret = -EOPNOTSUPP; |
870 | goto err_pci_free_region; |
871 | } |
872 | |
873 | ret = ath11k_pcic_init_msi_config(ab); |
874 | if (ret) { |
875 | ath11k_err(ab, fmt: "failed to init msi config: %d\n" , ret); |
876 | goto err_pci_free_region; |
877 | } |
878 | |
879 | ret = ath11k_pci_alloc_msi(ab_pci); |
880 | if (ret) { |
881 | ath11k_err(ab, fmt: "failed to enable msi: %d\n" , ret); |
882 | goto err_pci_free_region; |
883 | } |
884 | |
885 | ret = ath11k_core_pre_init(ab); |
886 | if (ret) |
887 | goto err_pci_disable_msi; |
888 | |
889 | ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); |
890 | if (ret) { |
891 | ath11k_err(ab, fmt: "failed to set irq affinity %d\n" , ret); |
892 | goto err_pci_disable_msi; |
893 | } |
894 | |
895 | ret = ath11k_mhi_register(ar_pci: ab_pci); |
896 | if (ret) { |
897 | ath11k_err(ab, fmt: "failed to register mhi: %d\n" , ret); |
898 | goto err_irq_affinity_cleanup; |
899 | } |
900 | |
901 | ret = ath11k_hal_srng_init(ath11k: ab); |
902 | if (ret) |
903 | goto err_mhi_unregister; |
904 | |
905 | ret = ath11k_ce_alloc_pipes(ab); |
906 | if (ret) { |
907 | ath11k_err(ab, fmt: "failed to allocate ce pipes: %d\n" , ret); |
908 | goto err_hal_srng_deinit; |
909 | } |
910 | |
911 | ath11k_pci_init_qmi_ce_config(ab); |
912 | |
913 | ret = ath11k_pcic_config_irq(ab); |
914 | if (ret) { |
915 | ath11k_err(ab, fmt: "failed to config irq: %d\n" , ret); |
916 | goto err_ce_free; |
917 | } |
918 | |
919 | /* kernel may allocate a dummy vector before request_irq and |
920 | * then allocate a real vector when request_irq is called. |
921 | * So get msi_data here again to avoid spurious interrupt |
922 | * as msi_data will configured to srngs. |
923 | */ |
924 | ret = ath11k_pci_config_msi_data(ab_pci); |
925 | if (ret) { |
926 | ath11k_err(ab, fmt: "failed to config msi_data: %d\n" , ret); |
927 | goto err_free_irq; |
928 | } |
929 | |
930 | ret = ath11k_core_init(ath11k: ab); |
931 | if (ret) { |
932 | ath11k_err(ab, fmt: "failed to init core: %d\n" , ret); |
933 | goto err_free_irq; |
934 | } |
935 | ath11k_qmi_fwreset_from_cold_boot(ab); |
936 | return 0; |
937 | |
938 | err_free_irq: |
939 | ath11k_pcic_free_irq(ab); |
940 | |
941 | err_ce_free: |
942 | ath11k_ce_free_pipes(ab); |
943 | |
944 | err_hal_srng_deinit: |
945 | ath11k_hal_srng_deinit(ath11k: ab); |
946 | |
947 | err_mhi_unregister: |
948 | ath11k_mhi_unregister(ar_pci: ab_pci); |
949 | |
950 | err_irq_affinity_cleanup: |
951 | ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); |
952 | |
953 | err_pci_disable_msi: |
954 | ath11k_pci_free_msi(ab_pci); |
955 | |
956 | err_pci_free_region: |
957 | ath11k_pci_free_region(ab_pci); |
958 | |
959 | err_free_core: |
960 | ath11k_core_free(ath11k: ab); |
961 | |
962 | return ret; |
963 | } |
964 | |
965 | static void ath11k_pci_remove(struct pci_dev *pdev) |
966 | { |
967 | struct ath11k_base *ab = pci_get_drvdata(pdev); |
968 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
969 | |
970 | ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); |
971 | |
972 | if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { |
973 | ath11k_pci_power_down(ab); |
974 | ath11k_debugfs_soc_destroy(ab); |
975 | ath11k_qmi_deinit_service(ab); |
976 | goto qmi_fail; |
977 | } |
978 | |
979 | set_bit(nr: ATH11K_FLAG_UNREGISTERING, addr: &ab->dev_flags); |
980 | |
981 | ath11k_core_deinit(ath11k: ab); |
982 | |
983 | qmi_fail: |
984 | ath11k_mhi_unregister(ar_pci: ab_pci); |
985 | |
986 | ath11k_pcic_free_irq(ab); |
987 | ath11k_pci_free_msi(ab_pci); |
988 | ath11k_pci_free_region(ab_pci); |
989 | |
990 | ath11k_hal_srng_deinit(ath11k: ab); |
991 | ath11k_ce_free_pipes(ab); |
992 | ath11k_core_free(ath11k: ab); |
993 | } |
994 | |
995 | static void ath11k_pci_shutdown(struct pci_dev *pdev) |
996 | { |
997 | struct ath11k_base *ab = pci_get_drvdata(pdev); |
998 | struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); |
999 | |
1000 | ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); |
1001 | ath11k_pci_power_down(ab); |
1002 | } |
1003 | |
1004 | static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) |
1005 | { |
1006 | struct ath11k_base *ab = dev_get_drvdata(dev); |
1007 | int ret; |
1008 | |
1009 | if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { |
1010 | ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n" ); |
1011 | return 0; |
1012 | } |
1013 | |
1014 | ret = ath11k_core_suspend(ab); |
1015 | if (ret) |
1016 | ath11k_warn(ab, fmt: "failed to suspend core: %d\n" , ret); |
1017 | |
1018 | return 0; |
1019 | } |
1020 | |
1021 | static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) |
1022 | { |
1023 | struct ath11k_base *ab = dev_get_drvdata(dev); |
1024 | int ret; |
1025 | |
1026 | if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { |
1027 | ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n" ); |
1028 | return 0; |
1029 | } |
1030 | |
1031 | ret = ath11k_core_resume(ab); |
1032 | if (ret) |
1033 | ath11k_warn(ab, fmt: "failed to resume core: %d\n" , ret); |
1034 | |
1035 | return ret; |
1036 | } |
1037 | |
1038 | static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, |
1039 | ath11k_pci_pm_suspend, |
1040 | ath11k_pci_pm_resume); |
1041 | |
1042 | static struct pci_driver ath11k_pci_driver = { |
1043 | .name = "ath11k_pci" , |
1044 | .id_table = ath11k_pci_id_table, |
1045 | .probe = ath11k_pci_probe, |
1046 | .remove = ath11k_pci_remove, |
1047 | .shutdown = ath11k_pci_shutdown, |
1048 | #ifdef CONFIG_PM |
1049 | .driver.pm = &ath11k_pci_pm_ops, |
1050 | #endif |
1051 | }; |
1052 | |
1053 | static int ath11k_pci_init(void) |
1054 | { |
1055 | int ret; |
1056 | |
1057 | ret = pci_register_driver(&ath11k_pci_driver); |
1058 | if (ret) |
1059 | pr_err("failed to register ath11k pci driver: %d\n" , |
1060 | ret); |
1061 | |
1062 | return ret; |
1063 | } |
1064 | module_init(ath11k_pci_init); |
1065 | |
1066 | static void ath11k_pci_exit(void) |
1067 | { |
1068 | pci_unregister_driver(dev: &ath11k_pci_driver); |
1069 | } |
1070 | |
1071 | module_exit(ath11k_pci_exit); |
1072 | |
1073 | MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11ax WLAN devices" ); |
1074 | MODULE_LICENSE("Dual BSD/GPL" ); |
1075 | |
1076 | /* firmware files */ |
1077 | MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/*" ); |
1078 | MODULE_FIRMWARE(ATH11K_FW_DIR "/QCN9074/hw1.0/*" ); |
1079 | MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.0/*" ); |
1080 | MODULE_FIRMWARE(ATH11K_FW_DIR "/WCN6855/hw2.1/*" ); |
1081 | |