blob: 47da1b3e4c095ce13b83329e2bf82f9fe356abfd [file] [log] [blame]
Lior David639ebed2017-02-28 14:23:55 +02001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/of.h>
16#include <linux/of_gpio.h>
17#include <linux/msm_pcie.h>
18#include <asm/dma-iommu.h>
19#include <linux/msm-bus.h>
20#include <linux/iommu.h>
21#include <linux/version.h>
22#include <linux/delay.h>
23#include <soc/qcom/subsystem_restart.h>
24#include <soc/qcom/subsystem_notif.h>
25#include <soc/qcom/ramdump.h>
26#include <soc/qcom/memory_dump.h>
27#include <linux/regulator/consumer.h>
28#include <linux/clk.h>
Lior Daviddb711962017-02-15 21:04:55 +020029#include <linux/interrupt.h>
30#include <linux/cpumask.h>
31#include <linux/cpufreq.h>
32#include <linux/sched/core_ctl.h>
Lior David639ebed2017-02-28 14:23:55 +020033#include "wil_platform.h"
34#include "msm_11ad.h"
35
36#define WIGIG_VENDOR (0x1ae9)
37#define WIGIG_DEVICE (0x0310)
38
39#define SMMU_BASE 0x10000000 /* Device address range base */
40#define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE)
41
42#define WIGIG_ENABLE_DELAY 50
43#define PM_OPT_SUSPEND (MSM_PCIE_CONFIG_NO_CFG_RESTORE | \
44 MSM_PCIE_CONFIG_LINKDOWN)
45#define PM_OPT_RESUME MSM_PCIE_CONFIG_NO_CFG_RESTORE
46
47#define WIGIG_SUBSYS_NAME "WIGIG"
48#define WIGIG_RAMDUMP_SIZE 0x200000 /* maximum ramdump size */
49#define WIGIG_DUMP_FORMAT_VER 0x1
50#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
51#define VDD_MIN_UV 1028000
52#define VDD_MAX_UV 1028000
53#define VDD_MAX_UA 575000
54#define VDDIO_MIN_UV 1950000
55#define VDDIO_MAX_UV 2040000
56#define VDDIO_MAX_UA 70300
57
Maya Erez17ef6c32017-03-27 08:37:07 +030058#define PCIE20_CAP_LINKCTRLSTATUS 0x80
59
Maya Erez3ef3e362017-03-27 08:47:02 +030060#define WIGIG_MIN_CPU_BOOST_KBPS 150000
61
Lior David639ebed2017-02-28 14:23:55 +020062struct device;
63
64static const char * const gpio_en_name = "qcom,wigig-en";
65static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
66
67struct msm11ad_vreg {
68 const char *name;
69 struct regulator *reg;
70 int max_uA;
71 int min_uV;
72 int max_uV;
73 bool enabled;
74};
75
76struct msm11ad_clk {
77 const char *name;
78 struct clk *clk;
79 bool enabled;
80};
81
82struct msm11ad_ctx {
83 struct list_head list;
84 struct device *dev; /* for platform device */
85 int gpio_en; /* card enable */
86 int sleep_clk_en; /* sleep clock enable for low PM management */
87
88 /* pci device */
89 u32 rc_index; /* PCIE root complex index */
90 struct pci_dev *pcidev;
91 struct pci_saved_state *pristine_state;
Maya Erez3ef3e362017-03-27 08:47:02 +030092 bool l1_enabled_in_enum;
Lior David639ebed2017-02-28 14:23:55 +020093
94 /* SMMU */
95 bool use_smmu; /* have SMMU enabled? */
96 int smmu_bypass;
97 int smmu_fast_map;
98 struct dma_iommu_mapping *mapping;
99
100 /* bus frequency scaling */
101 struct msm_bus_scale_pdata *bus_scale;
102 u32 msm_bus_handle;
103
104 /* subsystem restart */
105 struct wil_platform_rops rops;
106 void *wil_handle;
107 struct subsys_desc subsysdesc;
108 struct subsys_device *subsys;
109 void *subsys_handle;
110 bool recovery_in_progress;
111
112 /* ramdump */
113 void *ramdump_addr;
114 struct msm_dump_data dump_data;
115 struct ramdump_device *ramdump_dev;
116
117 /* external vregs and clocks */
118 struct msm11ad_vreg vdd;
119 struct msm11ad_vreg vddio;
120 struct msm11ad_clk rf_clk3;
121 struct msm11ad_clk rf_clk3_pin;
Lior Daviddb711962017-02-15 21:04:55 +0200122
123 /* cpu boost support */
124 bool use_cpu_boost;
125 bool is_cpu_boosted;
126 struct cpumask boost_cpu;
Lior David639ebed2017-02-28 14:23:55 +0200127};
128
129static LIST_HEAD(dev_list);
130
131static struct msm11ad_ctx *pcidev2ctx(struct pci_dev *pcidev)
132{
133 struct msm11ad_ctx *ctx;
134
135 list_for_each_entry(ctx, &dev_list, list) {
136 if (ctx->pcidev == pcidev)
137 return ctx;
138 }
139 return NULL;
140}
141
142static int msm_11ad_init_vreg(struct device *dev,
143 struct msm11ad_vreg *vreg, const char *name)
144{
145 int rc = 0;
146
147 if (!vreg)
148 return 0;
149
150 vreg->name = kstrdup(name, GFP_KERNEL);
151 if (!vreg->name)
152 return -ENOMEM;
153
154 vreg->reg = devm_regulator_get(dev, name);
155 if (IS_ERR_OR_NULL(vreg->reg)) {
156 rc = PTR_ERR(vreg->reg);
157 dev_err(dev, "%s: failed to get %s, rc=%d\n",
158 __func__, name, rc);
159 kfree(vreg->name);
160 vreg->reg = NULL;
161 goto out;
162 }
163
164 dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
165
166out:
167 return rc;
168}
169
170static int msm_11ad_release_vreg(struct device *dev, struct msm11ad_vreg *vreg)
171{
172 if (!vreg || !vreg->reg)
173 return 0;
174
175 dev_info(dev, "%s: %s released\n", __func__, vreg->name);
176
177 devm_regulator_put(vreg->reg);
178 vreg->reg = NULL;
179 kfree(vreg->name);
180
181 return 0;
182}
183
184static int msm_11ad_init_clk(struct device *dev, struct msm11ad_clk *clk,
185 const char *name)
186{
187 int rc = 0;
188
189 clk->name = kstrdup(name, GFP_KERNEL);
190 if (!clk->name)
191 return -ENOMEM;
192
193 clk->clk = devm_clk_get(dev, name);
194 if (IS_ERR(clk->clk)) {
195 rc = PTR_ERR(clk->clk);
196 if (rc == -ENOENT)
197 rc = -EPROBE_DEFER;
198 dev_err(dev, "%s: failed to get %s rc %d",
199 __func__, name, rc);
200 kfree(clk->name);
201 clk->clk = NULL;
202 goto out;
203 }
204
205 dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
206
207out:
208 return rc;
209}
210
211static int msm_11ad_release_clk(struct device *dev, struct msm11ad_clk *clk)
212{
213 if (!clk || !clk->clk)
214 return 0;
215
216 dev_info(dev, "%s: %s released\n", __func__, clk->name);
217
218 devm_clk_put(dev, clk->clk);
219 clk->clk = NULL;
220
221 kfree(clk->name);
222
223 return 0;
224}
225
226static int msm_11ad_init_vregs(struct msm11ad_ctx *ctx)
227{
228 int rc;
229 struct device *dev = ctx->dev;
230
231 if (!of_property_read_bool(dev->of_node, "qcom,use-ext-supply"))
232 return 0;
233
234 rc = msm_11ad_init_vreg(dev, &ctx->vdd, "vdd");
235 if (rc)
236 goto out;
237
238 ctx->vdd.max_uV = VDD_MAX_UV;
239 ctx->vdd.min_uV = VDD_MIN_UV;
240 ctx->vdd.max_uA = VDD_MAX_UA;
241
242 rc = msm_11ad_init_vreg(dev, &ctx->vddio, "vddio");
243 if (rc)
244 goto vddio_fail;
245
246 ctx->vddio.max_uV = VDDIO_MAX_UV;
247 ctx->vddio.min_uV = VDDIO_MIN_UV;
248 ctx->vddio.max_uA = VDDIO_MAX_UA;
249
250 return rc;
251
252vddio_fail:
253 msm_11ad_release_vreg(dev, &ctx->vdd);
254out:
255 return rc;
256}
257
258static void msm_11ad_release_vregs(struct msm11ad_ctx *ctx)
259{
260 msm_11ad_release_vreg(ctx->dev, &ctx->vdd);
261 msm_11ad_release_vreg(ctx->dev, &ctx->vddio);
262}
263
264static int msm_11ad_cfg_vreg(struct device *dev,
265 struct msm11ad_vreg *vreg, bool on)
266{
267 int rc = 0;
268 int min_uV;
269 int uA_load;
270
271 if (!vreg || !vreg->reg)
272 goto out;
273
274 if (regulator_count_voltages(vreg->reg) > 0) {
275 min_uV = on ? vreg->min_uV : 0;
276 rc = regulator_set_voltage(vreg->reg, min_uV, vreg->max_uV);
277 if (rc) {
278 dev_err(dev, "%s: %s set voltage failed, err=%d\n",
279 __func__, vreg->name, rc);
280 goto out;
281 }
282 uA_load = on ? vreg->max_uA : 0;
283 rc = regulator_set_load(vreg->reg, uA_load);
284 if (rc >= 0) {
285 /*
286 * regulator_set_load() returns new regulator
287 * mode upon success.
288 */
289 dev_dbg(dev,
290 "%s: %s regulator_set_load rc(%d)\n",
291 __func__, vreg->name, rc);
292 rc = 0;
293 } else {
294 dev_err(dev,
295 "%s: %s set load(uA_load=%d) failed, rc=%d\n",
296 __func__, vreg->name, uA_load, rc);
297 goto out;
298 }
299 }
300
301out:
302 return rc;
303}
304
305static int msm_11ad_enable_vreg(struct msm11ad_ctx *ctx,
306 struct msm11ad_vreg *vreg)
307{
308 struct device *dev = ctx->dev;
309 int rc = 0;
310
311 if (!vreg || !vreg->reg || vreg->enabled)
312 goto out;
313
314 rc = msm_11ad_cfg_vreg(dev, vreg, true);
315 if (rc)
316 goto out;
317
318 rc = regulator_enable(vreg->reg);
319 if (rc) {
320 dev_err(dev, "%s: %s enable failed, rc=%d\n",
321 __func__, vreg->name, rc);
322 goto enable_fail;
323 }
324
325 vreg->enabled = true;
326
327 dev_info(dev, "%s: %s enabled\n", __func__, vreg->name);
328
329 return rc;
330
331enable_fail:
332 msm_11ad_cfg_vreg(dev, vreg, false);
333out:
334 return rc;
335}
336
337static int msm_11ad_disable_vreg(struct msm11ad_ctx *ctx,
338 struct msm11ad_vreg *vreg)
339{
340 struct device *dev = ctx->dev;
341 int rc = 0;
342
343 if (!vreg || !vreg->reg || !vreg->enabled)
344 goto out;
345
346 rc = regulator_disable(vreg->reg);
347 if (rc) {
348 dev_err(dev, "%s: %s disable failed, rc=%d\n",
349 __func__, vreg->name, rc);
350 goto out;
351 }
352
353 /* ignore errors on applying disable config */
354 msm_11ad_cfg_vreg(dev, vreg, false);
355 vreg->enabled = false;
356
357 dev_info(dev, "%s: %s disabled\n", __func__, vreg->name);
358
359out:
360 return rc;
361}
362
363static int msm_11ad_enable_vregs(struct msm11ad_ctx *ctx)
364{
365 int rc = 0;
366
367 rc = msm_11ad_enable_vreg(ctx, &ctx->vdd);
368 if (rc)
369 goto out;
370
371 rc = msm_11ad_enable_vreg(ctx, &ctx->vddio);
372 if (rc)
373 goto vddio_fail;
374
375 return rc;
376
377vddio_fail:
378 msm_11ad_disable_vreg(ctx, &ctx->vdd);
379out:
380 return rc;
381}
382
383static int msm_11ad_disable_vregs(struct msm11ad_ctx *ctx)
384{
385 if (!ctx->vdd.reg && !ctx->vddio.reg)
386 goto out;
387
388 /* ignore errors on disable vreg */
389 msm_11ad_disable_vreg(ctx, &ctx->vdd);
390 msm_11ad_disable_vreg(ctx, &ctx->vddio);
391
392out:
393 return 0;
394}
395
396static int msm_11ad_enable_clk(struct msm11ad_ctx *ctx,
397 struct msm11ad_clk *clk)
398{
399 struct device *dev = ctx->dev;
400 int rc = 0;
401
402 if (!clk || !clk->clk || clk->enabled)
403 goto out;
404
405 rc = clk_prepare_enable(clk->clk);
406 if (rc) {
407 dev_err(dev, "%s: failed to enable %s, rc(%d)\n",
408 __func__, clk->name, rc);
409 goto out;
410 }
411 clk->enabled = true;
412
413 dev_dbg(dev, "%s: %s enabled\n", __func__, clk->name);
414
415out:
416 return rc;
417}
418
419static void msm_11ad_disable_clk(struct msm11ad_ctx *ctx,
420 struct msm11ad_clk *clk)
421{
422 struct device *dev = ctx->dev;
423
424 if (!clk || !clk->clk || !clk->enabled)
425 goto out;
426
427 clk_disable_unprepare(clk->clk);
428 clk->enabled = false;
429
430 dev_dbg(dev, "%s: %s disabled\n", __func__, clk->name);
431
432out:
433 return;
434}
435
436static int msm_11ad_enable_clocks(struct msm11ad_ctx *ctx)
437{
438 int rc;
439
440 rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3);
441 if (rc)
442 return rc;
443
444 rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3_pin);
445 if (rc)
446 msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
447
448 return rc;
449}
450
451static int msm_11ad_init_clocks(struct msm11ad_ctx *ctx)
452{
453 int rc;
454 struct device *dev = ctx->dev;
455
456 if (!of_property_read_bool(dev->of_node, "qcom,use-ext-clocks"))
457 return 0;
458
459 rc = msm_11ad_init_clk(dev, &ctx->rf_clk3, "rf_clk3_clk");
460 if (rc)
461 return rc;
462
463 rc = msm_11ad_init_clk(dev, &ctx->rf_clk3_pin, "rf_clk3_pin_clk");
464 if (rc)
465 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
466
467 return rc;
468}
469
470static void msm_11ad_release_clocks(struct msm11ad_ctx *ctx)
471{
472 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3_pin);
473 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
474}
475
476static void msm_11ad_disable_clocks(struct msm11ad_ctx *ctx)
477{
478 msm_11ad_disable_clk(ctx, &ctx->rf_clk3_pin);
479 msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
480}
481
Maya Erez3ef3e362017-03-27 08:47:02 +0300482int msm_11ad_ctrl_aspm_l1(struct msm11ad_ctx *ctx, bool enable)
483{
484 int rc;
485 u32 val;
486 struct pci_dev *pdev = ctx->pcidev;
487 bool l1_enabled;
488
489 /* Read current state */
490 rc = pci_read_config_dword(pdev,
491 PCIE20_CAP_LINKCTRLSTATUS, &val);
492 if (rc) {
493 dev_err(ctx->dev,
494 "reading PCIE20_CAP_LINKCTRLSTATUS failed:%d\n", rc);
495 return rc;
496 }
497 dev_dbg(ctx->dev, "PCIE20_CAP_LINKCTRLSTATUS read returns 0x%x\n", val);
498
499 l1_enabled = val & PCI_EXP_LNKCTL_ASPM_L1;
500 if (l1_enabled == enable) {
501 dev_dbg(ctx->dev, "ASPM_L1 is already %s\n",
502 l1_enabled ? "enabled" : "disabled");
503 return 0;
504 }
505
506 if (enable)
507 val |= PCI_EXP_LNKCTL_ASPM_L1; /* enable bit 1 */
508 else
509 val &= ~PCI_EXP_LNKCTL_ASPM_L1; /* disable bit 1 */
510
511 dev_dbg(ctx->dev, "writing PCIE20_CAP_LINKCTRLSTATUS (val 0x%x)\n",
512 val);
513 rc = pci_write_config_dword(pdev,
514 PCIE20_CAP_LINKCTRLSTATUS, val);
515 if (rc)
516 dev_err(ctx->dev,
517 "writing PCIE20_CAP_LINKCTRLSTATUS (val 0x%x) failed:%d\n",
518 val, rc);
519
520 return rc;
521}
522
Lior David639ebed2017-02-28 14:23:55 +0200523static int ops_suspend(void *handle)
524{
525 int rc;
526 struct msm11ad_ctx *ctx = handle;
527 struct pci_dev *pcidev;
528
529 pr_info("%s(%p)\n", __func__, handle);
530 if (!ctx) {
531 pr_err("No context\n");
532 return -ENODEV;
533 }
534 pcidev = ctx->pcidev;
535 rc = pci_save_state(pcidev);
536 if (rc) {
537 dev_err(ctx->dev, "pci_save_state failed :%d\n", rc);
538 return rc;
539 }
540 rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
541 pcidev, NULL, PM_OPT_SUSPEND);
542 if (rc) {
543 dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n",
544 rc);
545 return rc;
546 }
547 if (ctx->gpio_en >= 0)
548 gpio_direction_output(ctx->gpio_en, 0);
549
550 if (ctx->sleep_clk_en >= 0)
551 gpio_direction_output(ctx->sleep_clk_en, 0);
552
553 msm_11ad_disable_clocks(ctx);
554
555 msm_11ad_disable_vregs(ctx);
556
557 return rc;
558}
559
560static int ops_resume(void *handle)
561{
562 int rc;
563 struct msm11ad_ctx *ctx = handle;
564 struct pci_dev *pcidev;
565
566 pr_info("%s(%p)\n", __func__, handle);
567 if (!ctx) {
568 pr_err("No context\n");
569 return -ENODEV;
570 }
571
572 rc = msm_11ad_enable_vregs(ctx);
573 if (rc) {
574 dev_err(ctx->dev, "msm_11ad_enable_vregs failed :%d\n",
575 rc);
576 return rc;
577 }
578
579 rc = msm_11ad_enable_clocks(ctx);
580 if (rc) {
581 dev_err(ctx->dev, "msm_11ad_enable_clocks failed :%d\n", rc);
582 goto err_disable_vregs;
583 }
584
585 if (ctx->sleep_clk_en >= 0)
586 gpio_direction_output(ctx->sleep_clk_en, 1);
587
588 pcidev = ctx->pcidev;
589 if (ctx->gpio_en >= 0) {
590 gpio_direction_output(ctx->gpio_en, 1);
591 msleep(WIGIG_ENABLE_DELAY);
592 }
593
594 rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
595 pcidev, NULL, PM_OPT_RESUME);
596 if (rc) {
597 dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n",
598 rc);
599 goto err_disable_power;
600 }
601 rc = msm_pcie_recover_config(pcidev);
602 if (rc) {
603 dev_err(ctx->dev, "msm_pcie_recover_config failed :%d\n",
604 rc);
605 goto err_suspend_rc;
606 }
607
Maya Erez3ef3e362017-03-27 08:47:02 +0300608 /* Disable L1, in case it is enabled */
609 if (ctx->l1_enabled_in_enum) {
610 rc = msm_11ad_ctrl_aspm_l1(ctx, false);
611 if (rc) {
612 dev_err(ctx->dev,
613 "failed to disable L1, rc %d\n", rc);
614 goto err_suspend_rc;
615 }
Maya Erez17ef6c32017-03-27 08:37:07 +0300616 }
617
Lior David639ebed2017-02-28 14:23:55 +0200618 return 0;
619
620err_suspend_rc:
621 msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
622 pcidev, NULL, PM_OPT_SUSPEND);
623err_disable_power:
624 if (ctx->gpio_en >= 0)
625 gpio_direction_output(ctx->gpio_en, 0);
626
627 if (ctx->sleep_clk_en >= 0)
628 gpio_direction_output(ctx->sleep_clk_en, 0);
629
630 msm_11ad_disable_clocks(ctx);
631err_disable_vregs:
632 msm_11ad_disable_vregs(ctx);
633
634 return rc;
635}
636
637static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
638{
639 int atomic_ctx = 1;
640 int rc;
641
642 if (!ctx->use_smmu)
643 return 0;
644
645 dev_info(ctx->dev, "Initialize SMMU, bypass = %d, fastmap = %d\n",
646 ctx->smmu_bypass, ctx->smmu_fast_map);
647
648 ctx->mapping = arm_iommu_create_mapping(&platform_bus_type,
649 SMMU_BASE, SMMU_SIZE);
650 if (IS_ERR_OR_NULL(ctx->mapping)) {
651 rc = PTR_ERR(ctx->mapping) ?: -ENODEV;
652 dev_err(ctx->dev, "Failed to create IOMMU mapping (%d)\n", rc);
653 return rc;
654 }
655
656 rc = iommu_domain_set_attr(ctx->mapping->domain,
657 DOMAIN_ATTR_ATOMIC,
658 &atomic_ctx);
659 if (rc) {
660 dev_err(ctx->dev, "Set atomic attribute to SMMU failed (%d)\n",
661 rc);
662 goto release_mapping;
663 }
664
665 if (ctx->smmu_bypass) {
666 rc = iommu_domain_set_attr(ctx->mapping->domain,
667 DOMAIN_ATTR_S1_BYPASS,
668 &ctx->smmu_bypass);
669 if (rc) {
670 dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
671 rc);
672 goto release_mapping;
673 }
674 } else if (ctx->smmu_fast_map) {
675 rc = iommu_domain_set_attr(ctx->mapping->domain,
676 DOMAIN_ATTR_FAST,
677 &ctx->smmu_fast_map);
678 if (rc) {
679 dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
680 rc);
681 goto release_mapping;
682 }
683 }
684
685 rc = arm_iommu_attach_device(&ctx->pcidev->dev, ctx->mapping);
686 if (rc) {
687 dev_err(ctx->dev, "arm_iommu_attach_device failed (%d)\n", rc);
688 goto release_mapping;
689 }
690 dev_info(ctx->dev, "attached to IOMMU\n");
691
692 return 0;
693release_mapping:
694 arm_iommu_release_mapping(ctx->mapping);
695 ctx->mapping = NULL;
696 return rc;
697}
698
699static int msm_11ad_ssr_shutdown(const struct subsys_desc *subsys,
700 bool force_stop)
701{
702 pr_info("%s(%p,%d)\n", __func__, subsys, force_stop);
703 /* nothing is done in shutdown. We do full recovery in powerup */
704 return 0;
705}
706
707static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys)
708{
709 int rc = 0;
710 struct platform_device *pdev;
711 struct msm11ad_ctx *ctx;
712
713 pr_info("%s(%p)\n", __func__, subsys);
714
715 pdev = to_platform_device(subsys->dev);
716 ctx = platform_get_drvdata(pdev);
717
718 if (!ctx)
719 return -ENODEV;
720
721 if (ctx->recovery_in_progress) {
722 if (ctx->rops.fw_recovery && ctx->wil_handle) {
723 dev_info(ctx->dev, "requesting FW recovery\n");
724 rc = ctx->rops.fw_recovery(ctx->wil_handle);
725 }
726 ctx->recovery_in_progress = false;
727 }
728
729 return rc;
730}
731
732static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
733{
734 int rc;
735 struct ramdump_segment segment;
736 struct platform_device *pdev;
737 struct msm11ad_ctx *ctx;
738
739 pdev = to_platform_device(subsys->dev);
740 ctx = platform_get_drvdata(pdev);
741
742 if (!ctx)
743 return -ENODEV;
744
745 if (!enable)
746 return 0;
747
748 if (ctx->rops.ramdump && ctx->wil_handle) {
749 rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
750 WIGIG_RAMDUMP_SIZE);
751 if (rc) {
752 dev_err(ctx->dev, "ramdump failed : %d\n", rc);
753 return -EINVAL;
754 }
755 }
756
757 memset(&segment, 0, sizeof(segment));
758 segment.v_address = ctx->ramdump_addr;
759 segment.size = WIGIG_RAMDUMP_SIZE;
760
761 return do_ramdump(ctx->ramdump_dev, &segment, 1);
762}
763
764static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys)
765{
766 int rc;
767 struct platform_device *pdev;
768 struct msm11ad_ctx *ctx;
769
770 pdev = to_platform_device(subsys->dev);
771 ctx = platform_get_drvdata(pdev);
772
773 if (!ctx) {
774 pr_err("%s: no context\n", __func__);
775 return;
776 }
777
778 if (ctx->rops.ramdump && ctx->wil_handle) {
779 rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
780 WIGIG_RAMDUMP_SIZE);
781 if (rc)
782 dev_err(ctx->dev, "ramdump failed : %d\n", rc);
783 /* continue */
784 }
785
786 ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER;
787 strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME,
788 sizeof(ctx->dump_data.name));
789
790 ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1;
791}
792
793static void msm_11ad_ssr_deinit(struct msm11ad_ctx *ctx)
794{
795 if (ctx->ramdump_dev) {
796 destroy_ramdump_device(ctx->ramdump_dev);
797 ctx->ramdump_dev = NULL;
798 }
799
800 kfree(ctx->ramdump_addr);
801 ctx->ramdump_addr = NULL;
802
803 if (ctx->subsys_handle) {
804 subsystem_put(ctx->subsys_handle);
805 ctx->subsys_handle = NULL;
806 }
807
808 if (ctx->subsys) {
809 subsys_unregister(ctx->subsys);
810 ctx->subsys = NULL;
811 }
812}
813
814static int msm_11ad_ssr_init(struct msm11ad_ctx *ctx)
815{
816 int rc;
817 struct msm_dump_entry dump_entry;
818
819 ctx->subsysdesc.name = "WIGIG";
820 ctx->subsysdesc.owner = THIS_MODULE;
821 ctx->subsysdesc.shutdown = msm_11ad_ssr_shutdown;
822 ctx->subsysdesc.powerup = msm_11ad_ssr_powerup;
823 ctx->subsysdesc.ramdump = msm_11ad_ssr_ramdump;
824 ctx->subsysdesc.crash_shutdown = msm_11ad_ssr_crash_shutdown;
825 ctx->subsysdesc.dev = ctx->dev;
826 ctx->subsys = subsys_register(&ctx->subsysdesc);
827 if (IS_ERR(ctx->subsys)) {
828 rc = PTR_ERR(ctx->subsys);
829 dev_err(ctx->dev, "subsys_register failed :%d\n", rc);
830 goto out_rc;
831 }
832
833 /* register ramdump area */
834 ctx->ramdump_addr = kmalloc(WIGIG_RAMDUMP_SIZE, GFP_KERNEL);
835 if (!ctx->ramdump_addr) {
836 rc = -ENOMEM;
837 goto out_rc;
838 }
839
840 ctx->dump_data.addr = virt_to_phys(ctx->ramdump_addr);
841 ctx->dump_data.len = WIGIG_RAMDUMP_SIZE;
842 dump_entry.id = MSM_DUMP_DATA_WIGIG;
843 dump_entry.addr = virt_to_phys(&ctx->dump_data);
844
845 rc = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
846 if (rc) {
847 dev_err(ctx->dev, "Dump table setup failed: %d\n", rc);
848 goto out_rc;
849 }
850
851 ctx->ramdump_dev = create_ramdump_device(ctx->subsysdesc.name,
852 ctx->subsysdesc.dev);
853 if (!ctx->ramdump_dev) {
854 dev_err(ctx->dev, "Create ramdump device failed: %d\n", rc);
855 rc = -ENOMEM;
856 goto out_rc;
857 }
858
859 return 0;
860
861out_rc:
862 msm_11ad_ssr_deinit(ctx);
863 return rc;
864}
865
Lior Daviddb711962017-02-15 21:04:55 +0200866static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx)
867{
868 unsigned int minfreq = 0, maxfreq = 0, freq;
869 int i, boost_cpu;
870
871 for_each_possible_cpu(i) {
872 freq = cpufreq_quick_get_max(i);
873 if (freq > maxfreq) {
874 maxfreq = freq;
875 boost_cpu = i;
876 }
877 if (!minfreq || freq < minfreq)
878 minfreq = freq;
879 }
880
881 if (minfreq != maxfreq) {
882 /*
883 * use first big core for boost, to be compatible with WLAN
884 * which assigns big cores from the last index
885 */
886 ctx->use_cpu_boost = true;
887 cpumask_clear(&ctx->boost_cpu);
888 cpumask_set_cpu(boost_cpu, &ctx->boost_cpu);
889 dev_info(ctx->dev, "CPU boost: will use core %d\n", boost_cpu);
890 } else {
891 ctx->use_cpu_boost = false;
892 dev_info(ctx->dev, "CPU boost disabled, uniform topology\n");
893 }
894}
895
Lior David639ebed2017-02-28 14:23:55 +0200896static int msm_11ad_probe(struct platform_device *pdev)
897{
898 struct msm11ad_ctx *ctx;
899 struct device *dev = &pdev->dev;
900 struct device_node *of_node = dev->of_node;
901 struct device_node *rc_node;
902 struct pci_dev *pcidev = NULL;
903 int rc;
Maya Erez17ef6c32017-03-27 08:37:07 +0300904 u32 val;
Lior David639ebed2017-02-28 14:23:55 +0200905
906 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
907 if (!ctx)
908 return -ENOMEM;
909
910 ctx->dev = dev;
911
912 /*== parse ==*/
913
914 /* Information pieces:
915 * - of_node stands for "wil6210":
916 * wil6210: qcom,wil6210 {
917 * compatible = "qcom,wil6210";
918 * qcom,pcie-parent = <&pcie1>;
919 * qcom,wigig-en = <&tlmm 94 0>; (ctx->gpio_en)
920 * qcom,sleep-clk-en = <&pm8994_gpios 18 0>; (ctx->sleep_clk_en)
921 * qcom,msm-bus,name = "wil6210";
922 * qcom,msm-bus,num-cases = <2>;
923 * qcom,msm-bus,num-paths = <1>;
924 * qcom,msm-bus,vectors-KBps =
925 * <100 512 0 0>,
926 * <100 512 600000 800000>;
927 * qcom,smmu-support;
928 *};
929 * rc_node stands for "qcom,pcie", selected entries:
930 * cell-index = <1>; (ctx->rc_index)
931 * iommus = <&anoc0_smmu>;
932 * qcom,smmu-exist;
933 */
934
935 /* wigig-en is optional property */
936 ctx->gpio_en = of_get_named_gpio(of_node, gpio_en_name, 0);
937 if (ctx->gpio_en < 0)
938 dev_warn(ctx->dev, "GPIO <%s> not found, enable GPIO not used\n",
939 gpio_en_name);
940 ctx->sleep_clk_en = of_get_named_gpio(of_node, sleep_clk_en_name, 0);
941 if (ctx->sleep_clk_en < 0)
942 dev_warn(ctx->dev, "GPIO <%s> not found, sleep clock not used\n",
943 sleep_clk_en_name);
944 rc_node = of_parse_phandle(of_node, "qcom,pcie-parent", 0);
945 if (!rc_node) {
946 dev_err(ctx->dev, "Parent PCIE device not found\n");
947 return -EINVAL;
948 }
949 rc = of_property_read_u32(rc_node, "cell-index", &ctx->rc_index);
950 if (rc < 0) {
951 dev_err(ctx->dev, "Parent PCIE device index not found\n");
952 return -EINVAL;
953 }
954 ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support");
955 ctx->bus_scale = msm_bus_cl_get_pdata(pdev);
956
957 ctx->smmu_bypass = 1;
958 ctx->smmu_fast_map = 0;
959
960 /*== execute ==*/
961 /* turn device on */
962 rc = msm_11ad_init_vregs(ctx);
963 if (rc) {
964 dev_err(ctx->dev, "msm_11ad_init_vregs failed: %d\n", rc);
965 return rc;
966 }
967 rc = msm_11ad_enable_vregs(ctx);
968 if (rc) {
969 dev_err(ctx->dev, "msm_11ad_enable_vregs failed: %d\n", rc);
970 goto out_vreg_clk;
971 }
972
973 rc = msm_11ad_init_clocks(ctx);
974 if (rc) {
975 dev_err(ctx->dev, "msm_11ad_init_clocks failed: %d\n", rc);
976 goto out_vreg_clk;
977 }
978
979 rc = msm_11ad_enable_clocks(ctx);
980 if (rc) {
981 dev_err(ctx->dev, "msm_11ad_enable_clocks failed: %d\n", rc);
982 goto out_vreg_clk;
983 }
984
985 if (ctx->gpio_en >= 0) {
986 rc = gpio_request(ctx->gpio_en, gpio_en_name);
987 if (rc < 0) {
988 dev_err(ctx->dev, "failed to request GPIO %d <%s>\n",
989 ctx->gpio_en, gpio_en_name);
990 goto out_req;
991 }
992 rc = gpio_direction_output(ctx->gpio_en, 1);
993 if (rc < 0) {
994 dev_err(ctx->dev, "failed to set GPIO %d <%s>\n",
995 ctx->gpio_en, gpio_en_name);
996 goto out_set;
997 }
998 msleep(WIGIG_ENABLE_DELAY);
999 }
1000
1001 /* enumerate it on PCIE */
1002 rc = msm_pcie_enumerate(ctx->rc_index);
1003 if (rc < 0) {
1004 dev_err(ctx->dev, "Parent PCIE enumeration failed\n");
1005 goto out_rc;
1006 }
1007 /* search for PCIE device in our domain */
1008 do {
1009 pcidev = pci_get_device(WIGIG_VENDOR, WIGIG_DEVICE, pcidev);
1010 if (!pcidev)
1011 break;
1012
1013 if (pci_domain_nr(pcidev->bus) == ctx->rc_index)
1014 break;
1015 } while (true);
1016 if (!pcidev) {
1017 rc = -ENODEV;
1018 dev_err(ctx->dev, "Wigig device %4x:%4x not found\n",
1019 WIGIG_VENDOR, WIGIG_DEVICE);
1020 goto out_rc;
1021 }
1022 ctx->pcidev = pcidev;
Maya Erez17ef6c32017-03-27 08:37:07 +03001023
Maya Erez3ef3e362017-03-27 08:47:02 +03001024 /* Read current state */
1025 rc = pci_read_config_dword(pcidev,
Maya Erez17ef6c32017-03-27 08:37:07 +03001026 PCIE20_CAP_LINKCTRLSTATUS, &val);
1027 if (rc) {
1028 dev_err(ctx->dev,
1029 "reading PCIE20_CAP_LINKCTRLSTATUS failed:%d\n",
1030 rc);
1031 goto out_rc;
1032 }
Maya Erez3ef3e362017-03-27 08:47:02 +03001033
1034 ctx->l1_enabled_in_enum = val & PCI_EXP_LNKCTL_ASPM_L1;
1035 dev_dbg(ctx->dev, "L1 is %s in enumeration\n",
1036 ctx->l1_enabled_in_enum ? "enabled" : "disabled");
1037
1038 /* Disable L1, in case it is enabled */
1039 if (ctx->l1_enabled_in_enum) {
1040 rc = msm_11ad_ctrl_aspm_l1(ctx, false);
1041 if (rc) {
1042 dev_err(ctx->dev,
1043 "failed to disable L1, rc %d\n", rc);
1044 goto out_rc;
1045 }
Maya Erez17ef6c32017-03-27 08:37:07 +03001046 }
1047
Lior David639ebed2017-02-28 14:23:55 +02001048 rc = pci_save_state(pcidev);
1049 if (rc) {
1050 dev_err(ctx->dev, "pci_save_state failed :%d\n", rc);
1051 goto out_rc;
1052 }
1053 ctx->pristine_state = pci_store_saved_state(pcidev);
1054
1055 if (ctx->sleep_clk_en >= 0) {
1056 rc = gpio_request(ctx->sleep_clk_en, "msm_11ad");
1057 if (rc < 0) {
1058 dev_err(ctx->dev,
1059 "failed to request GPIO %d <%s>, sleep clock disabled\n",
1060 ctx->sleep_clk_en, sleep_clk_en_name);
1061 ctx->sleep_clk_en = -EINVAL;
1062 } else {
1063 gpio_direction_output(ctx->sleep_clk_en, 0);
1064 }
1065 }
1066
1067 /* register for subsystem restart */
1068 rc = msm_11ad_ssr_init(ctx);
1069 if (rc) {
1070 dev_err(ctx->dev, "msm_11ad_ssr_init failed: %d\n", rc);
1071 goto out_rc;
1072 }
1073
Lior Daviddb711962017-02-15 21:04:55 +02001074 msm_11ad_init_cpu_boost(ctx);
1075
Lior David639ebed2017-02-28 14:23:55 +02001076 /* report */
1077 dev_info(ctx->dev, "msm_11ad discovered. %p {\n"
1078 " gpio_en = %d\n"
1079 " sleep_clk_en = %d\n"
1080 " rc_index = %d\n"
1081 " use_smmu = %d\n"
1082 " pcidev = %p\n"
1083 "}\n", ctx, ctx->gpio_en, ctx->sleep_clk_en, ctx->rc_index,
1084 ctx->use_smmu, ctx->pcidev);
1085
1086 platform_set_drvdata(pdev, ctx);
1087 device_disable_async_suspend(&pcidev->dev);
1088
1089 list_add_tail(&ctx->list, &dev_list);
1090 ops_suspend(ctx);
1091
1092 return 0;
1093out_rc:
1094 if (ctx->gpio_en >= 0)
1095 gpio_direction_output(ctx->gpio_en, 0);
1096out_set:
1097 if (ctx->gpio_en >= 0)
1098 gpio_free(ctx->gpio_en);
1099out_req:
1100 ctx->gpio_en = -EINVAL;
1101out_vreg_clk:
1102 msm_11ad_disable_clocks(ctx);
1103 msm_11ad_release_clocks(ctx);
1104 msm_11ad_disable_vregs(ctx);
1105 msm_11ad_release_vregs(ctx);
1106
1107 return rc;
1108}
1109
1110static int msm_11ad_remove(struct platform_device *pdev)
1111{
1112 struct msm11ad_ctx *ctx = platform_get_drvdata(pdev);
1113
1114 msm_11ad_ssr_deinit(ctx);
1115 list_del(&ctx->list);
1116 dev_info(ctx->dev, "%s: pdev %p pcidev %p\n", __func__, pdev,
1117 ctx->pcidev);
1118 kfree(ctx->pristine_state);
1119
1120 msm_bus_cl_clear_pdata(ctx->bus_scale);
1121 pci_dev_put(ctx->pcidev);
1122 if (ctx->gpio_en >= 0) {
1123 gpio_direction_output(ctx->gpio_en, 0);
1124 gpio_free(ctx->gpio_en);
1125 }
1126 if (ctx->sleep_clk_en >= 0)
1127 gpio_free(ctx->sleep_clk_en);
1128
1129 msm_11ad_disable_clocks(ctx);
1130 msm_11ad_release_clocks(ctx);
1131 msm_11ad_disable_vregs(ctx);
1132 msm_11ad_release_vregs(ctx);
1133
1134 return 0;
1135}
1136
1137static const struct of_device_id msm_11ad_of_match[] = {
1138 { .compatible = "qcom,wil6210", },
1139 {},
1140};
1141
1142static struct platform_driver msm_11ad_driver = {
1143 .driver = {
1144 .name = "msm_11ad",
1145 .of_match_table = msm_11ad_of_match,
1146 },
1147 .probe = msm_11ad_probe,
1148 .remove = msm_11ad_remove,
1149};
1150module_platform_driver(msm_11ad_driver);
1151
Lior Daviddb711962017-02-15 21:04:55 +02001152static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx)
1153{
1154 /*
1155 * There is a very small window where user space can change the
1156 * affinity after we changed it here and before setting the
1157 * NO_BALANCING flag. Retry this several times as a workaround.
1158 */
1159 int retries = 5, rc;
1160 struct irq_desc *desc;
1161
1162 while (retries > 0) {
1163 irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0);
1164 rc = irq_set_affinity_hint(ctx->pcidev->irq, &ctx->boost_cpu);
1165 if (rc)
1166 dev_warn(ctx->dev,
1167 "Failed set affinity, rc=%d\n", rc);
1168 irq_modify_status(ctx->pcidev->irq, 0, IRQ_NO_BALANCING);
1169 desc = irq_to_desc(ctx->pcidev->irq);
1170 if (cpumask_equal(desc->irq_common_data.affinity,
1171 &ctx->boost_cpu))
1172 break;
1173 retries--;
1174 }
1175
1176 if (!retries)
1177 dev_warn(ctx->dev, "failed to set CPU boost affinity\n");
1178}
1179
Lior David639ebed2017-02-28 14:23:55 +02001180/* hooks for the wil6210 driver */
1181static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */)
1182{
1183 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1184 int rc, i;
1185 int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
1186 struct msm_bus_paths *usecase;
1187 u32 usecase_kbps;
1188 u32 min_kbps = ~0;
1189
1190 /* find the lowest usecase that is bigger than requested kbps */
1191 for (i = 0; i < ctx->bus_scale->num_usecases; i++) {
1192 usecase = &ctx->bus_scale->usecase[i];
1193 /*
1194 * assume we have single path (vectors[0]). If we ever
1195 * have multiple paths, need to define the behavior
1196 */
1197 usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
1198 if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
1199 min_kbps = usecase_kbps;
1200 vote = i;
1201 }
1202 }
1203
1204 rc = msm_bus_scale_client_update_request(ctx->msm_bus_handle, vote);
1205 if (rc)
1206 dev_err(ctx->dev,
1207 "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
1208 kbps, vote, rc);
1209
Lior Daviddb711962017-02-15 21:04:55 +02001210 if (ctx->use_cpu_boost) {
1211 bool was_boosted = ctx->is_cpu_boosted;
1212 bool needs_boost = (kbps >= WIGIG_MIN_CPU_BOOST_KBPS);
1213
1214 if (was_boosted != needs_boost) {
1215 if (needs_boost) {
1216 rc = core_ctl_set_boost(true);
1217 if (rc) {
1218 dev_err(ctx->dev,
1219 "Failed enable boost rc=%d\n",
1220 rc);
1221 goto out;
1222 }
1223 msm_11ad_set_boost_affinity(ctx);
1224 dev_dbg(ctx->dev, "CPU boost enabled\n");
1225 } else {
1226 rc = core_ctl_set_boost(false);
1227 if (rc)
1228 dev_err(ctx->dev,
1229 "Failed disable boost rc=%d\n",
1230 rc);
1231 irq_modify_status(ctx->pcidev->irq,
1232 IRQ_NO_BALANCING, 0);
1233 dev_dbg(ctx->dev, "CPU boost disabled\n");
1234 }
1235 ctx->is_cpu_boosted = needs_boost;
1236 }
1237 }
1238out:
Lior David639ebed2017-02-28 14:23:55 +02001239 return rc;
1240}
1241
1242static void ops_uninit(void *handle)
1243{
1244 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1245
1246 if (ctx->msm_bus_handle) {
1247 msm_bus_scale_unregister_client(ctx->msm_bus_handle);
1248 ctx->msm_bus_handle = 0;
1249 }
1250
1251 if (ctx->use_smmu) {
1252 arm_iommu_detach_device(&ctx->pcidev->dev);
1253 arm_iommu_release_mapping(ctx->mapping);
1254 ctx->mapping = NULL;
1255 }
1256
1257 memset(&ctx->rops, 0, sizeof(ctx->rops));
1258 ctx->wil_handle = NULL;
1259
1260 ops_suspend(ctx);
1261}
1262
1263static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx)
1264{
1265 int rc;
1266
1267 if (ctx->subsys) {
1268 dev_info(ctx->dev, "SSR requested\n");
1269 ctx->recovery_in_progress = true;
1270 rc = subsystem_restart_dev(ctx->subsys);
1271 if (rc) {
1272 dev_err(ctx->dev,
1273 "subsystem_restart_dev fail: %d\n", rc);
1274 ctx->recovery_in_progress = false;
1275 }
1276 }
1277
1278 return 0;
1279}
1280
1281static int ops_notify(void *handle, enum wil_platform_event evt)
1282{
1283 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1284 int rc = 0;
1285
1286 switch (evt) {
1287 case WIL_PLATFORM_EVT_FW_CRASH:
1288 rc = msm_11ad_notify_crash(ctx);
1289 break;
1290 case WIL_PLATFORM_EVT_PRE_RESET:
1291 /*
1292 * TODO: Enable rf_clk3 clock before resetting the device to
1293 * ensure stable ref clock during the device reset
1294 */
Maya Erez3ef3e362017-03-27 08:47:02 +03001295 /* Re-enable L1 in case it was enabled in enumeration */
1296 if (ctx->l1_enabled_in_enum) {
1297 rc = msm_11ad_ctrl_aspm_l1(ctx, true);
1298 if (rc)
1299 dev_err(ctx->dev,
1300 "failed to enable L1, rc %d\n", rc);
1301 }
Lior David639ebed2017-02-28 14:23:55 +02001302 break;
1303 case WIL_PLATFORM_EVT_FW_RDY:
1304 /*
1305 * TODO: Disable rf_clk3 clock after the device is up to allow
1306 * the device to control it via its GPIO for power saving
1307 */
1308 break;
1309 default:
1310 pr_debug("%s: Unhandled event %d\n", __func__, evt);
1311 break;
1312 }
1313
1314 return rc;
1315}
1316
1317void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops,
1318 const struct wil_platform_rops *rops, void *wil_handle)
1319{
1320 struct pci_dev *pcidev = to_pci_dev(dev);
1321 struct msm11ad_ctx *ctx = pcidev2ctx(pcidev);
1322
1323 if (!ctx) {
1324 pr_err("Context not found for pcidev %p\n", pcidev);
1325 return NULL;
1326 }
1327
1328 /* bus scale */
1329 ctx->msm_bus_handle =
1330 msm_bus_scale_register_client(ctx->bus_scale);
1331 if (!ctx->msm_bus_handle) {
1332 dev_err(ctx->dev, "Failed msm_bus registration\n");
1333 return NULL;
1334 }
1335 dev_info(ctx->dev, "msm_bus handle 0x%x\n", ctx->msm_bus_handle);
1336 /* smmu */
1337 if (msm_11ad_smmu_init(ctx)) {
1338 msm_bus_scale_unregister_client(ctx->msm_bus_handle);
1339 ctx->msm_bus_handle = 0;
1340 return NULL;
1341 }
1342
1343 /* subsystem restart */
1344 if (rops) {
1345 ctx->rops = *rops;
1346 ctx->wil_handle = wil_handle;
1347 }
1348
1349 /* fill ops */
1350 memset(ops, 0, sizeof(*ops));
1351 ops->bus_request = ops_bus_request;
1352 ops->suspend = ops_suspend;
1353 ops->resume = ops_resume;
1354 ops->uninit = ops_uninit;
1355 ops->notify = ops_notify;
1356
1357 return ctx;
1358}
1359EXPORT_SYMBOL(msm_11ad_dev_init);
1360
1361int msm_11ad_modinit(void)
1362{
1363 struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
1364 struct msm11ad_ctx,
1365 list);
1366
1367 if (!ctx) {
1368 pr_err("Context not found\n");
1369 return -EINVAL;
1370 }
1371
1372 if (ctx->pristine_state) {
1373 /* in old kernels, pci_load_saved_state() is not exported;
1374 * so use pci_load_and_free_saved_state()
1375 * and re-allocate ctx->saved_state again
1376 */
1377 pci_load_and_free_saved_state(ctx->pcidev,
1378 &ctx->pristine_state);
1379 ctx->pristine_state = pci_store_saved_state(ctx->pcidev);
1380 }
1381
1382 ctx->subsys_handle = subsystem_get(ctx->subsysdesc.name);
1383
1384 return ops_resume(ctx);
1385}
1386EXPORT_SYMBOL(msm_11ad_modinit);
1387
1388void msm_11ad_modexit(void)
1389{
1390 struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
1391 struct msm11ad_ctx,
1392 list);
1393
1394 if (!ctx) {
1395 pr_err("Context not found\n");
1396 return;
1397 }
1398
1399 if (ctx->subsys_handle) {
1400 subsystem_put(ctx->subsys_handle);
1401 ctx->subsys_handle = NULL;
1402 }
1403}
1404EXPORT_SYMBOL(msm_11ad_modexit);
1405
1406MODULE_LICENSE("GPL v2");
1407MODULE_DESCRIPTION("Platform driver for Qualcomm Technologies, Inc. 11ad card");
1408