]> Git Repo - linux.git/blob - drivers/accel/qaic/mhi_controller.c
net: wan: Add framer framework support
[linux.git] / drivers / accel / qaic / mhi_controller.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */
4 /* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
5
6 #include <linux/delay.h>
7 #include <linux/err.h>
8 #include <linux/memblock.h>
9 #include <linux/mhi.h>
10 #include <linux/moduleparam.h>
11 #include <linux/pci.h>
12 #include <linux/sizes.h>
13
14 #include "mhi_controller.h"
15 #include "qaic.h"
16
17 #define MAX_RESET_TIME_SEC 25
18
19 static unsigned int mhi_timeout_ms = 2000; /* 2 sec default */
20 module_param(mhi_timeout_ms, uint, 0600);
21 MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value");
22
23 static struct mhi_channel_config aic100_channels[] = {
24         {
25                 .name = "QAIC_LOOPBACK",
26                 .num = 0,
27                 .num_elements = 32,
28                 .local_elements = 0,
29                 .event_ring = 0,
30                 .dir = DMA_TO_DEVICE,
31                 .ee_mask = MHI_CH_EE_AMSS,
32                 .pollcfg = 0,
33                 .doorbell = MHI_DB_BRST_DISABLE,
34                 .lpm_notify = false,
35                 .offload_channel = false,
36                 .doorbell_mode_switch = false,
37                 .auto_queue = false,
38                 .wake_capable = false,
39         },
40         {
41                 .name = "QAIC_LOOPBACK",
42                 .num = 1,
43                 .num_elements = 32,
44                 .local_elements = 0,
45                 .event_ring = 0,
46                 .dir = DMA_FROM_DEVICE,
47                 .ee_mask = MHI_CH_EE_AMSS,
48                 .pollcfg = 0,
49                 .doorbell = MHI_DB_BRST_DISABLE,
50                 .lpm_notify = false,
51                 .offload_channel = false,
52                 .doorbell_mode_switch = false,
53                 .auto_queue = false,
54                 .wake_capable = false,
55         },
56         {
57                 .name = "QAIC_SAHARA",
58                 .num = 2,
59                 .num_elements = 32,
60                 .local_elements = 0,
61                 .event_ring = 0,
62                 .dir = DMA_TO_DEVICE,
63                 .ee_mask = MHI_CH_EE_SBL,
64                 .pollcfg = 0,
65                 .doorbell = MHI_DB_BRST_DISABLE,
66                 .lpm_notify = false,
67                 .offload_channel = false,
68                 .doorbell_mode_switch = false,
69                 .auto_queue = false,
70                 .wake_capable = false,
71         },
72         {
73                 .name = "QAIC_SAHARA",
74                 .num = 3,
75                 .num_elements = 32,
76                 .local_elements = 0,
77                 .event_ring = 0,
78                 .dir = DMA_FROM_DEVICE,
79                 .ee_mask = MHI_CH_EE_SBL,
80                 .pollcfg = 0,
81                 .doorbell = MHI_DB_BRST_DISABLE,
82                 .lpm_notify = false,
83                 .offload_channel = false,
84                 .doorbell_mode_switch = false,
85                 .auto_queue = false,
86                 .wake_capable = false,
87         },
88         {
89                 .name = "QAIC_DIAG",
90                 .num = 4,
91                 .num_elements = 32,
92                 .local_elements = 0,
93                 .event_ring = 0,
94                 .dir = DMA_TO_DEVICE,
95                 .ee_mask = MHI_CH_EE_AMSS,
96                 .pollcfg = 0,
97                 .doorbell = MHI_DB_BRST_DISABLE,
98                 .lpm_notify = false,
99                 .offload_channel = false,
100                 .doorbell_mode_switch = false,
101                 .auto_queue = false,
102                 .wake_capable = false,
103         },
104         {
105                 .name = "QAIC_DIAG",
106                 .num = 5,
107                 .num_elements = 32,
108                 .local_elements = 0,
109                 .event_ring = 0,
110                 .dir = DMA_FROM_DEVICE,
111                 .ee_mask = MHI_CH_EE_AMSS,
112                 .pollcfg = 0,
113                 .doorbell = MHI_DB_BRST_DISABLE,
114                 .lpm_notify = false,
115                 .offload_channel = false,
116                 .doorbell_mode_switch = false,
117                 .auto_queue = false,
118                 .wake_capable = false,
119         },
120         {
121                 .name = "QAIC_SSR",
122                 .num = 6,
123                 .num_elements = 32,
124                 .local_elements = 0,
125                 .event_ring = 0,
126                 .dir = DMA_TO_DEVICE,
127                 .ee_mask = MHI_CH_EE_AMSS,
128                 .pollcfg = 0,
129                 .doorbell = MHI_DB_BRST_DISABLE,
130                 .lpm_notify = false,
131                 .offload_channel = false,
132                 .doorbell_mode_switch = false,
133                 .auto_queue = false,
134                 .wake_capable = false,
135         },
136         {
137                 .name = "QAIC_SSR",
138                 .num = 7,
139                 .num_elements = 32,
140                 .local_elements = 0,
141                 .event_ring = 0,
142                 .dir = DMA_FROM_DEVICE,
143                 .ee_mask = MHI_CH_EE_AMSS,
144                 .pollcfg = 0,
145                 .doorbell = MHI_DB_BRST_DISABLE,
146                 .lpm_notify = false,
147                 .offload_channel = false,
148                 .doorbell_mode_switch = false,
149                 .auto_queue = false,
150                 .wake_capable = false,
151         },
152         {
153                 .name = "QAIC_QDSS",
154                 .num = 8,
155                 .num_elements = 32,
156                 .local_elements = 0,
157                 .event_ring = 0,
158                 .dir = DMA_TO_DEVICE,
159                 .ee_mask = MHI_CH_EE_AMSS,
160                 .pollcfg = 0,
161                 .doorbell = MHI_DB_BRST_DISABLE,
162                 .lpm_notify = false,
163                 .offload_channel = false,
164                 .doorbell_mode_switch = false,
165                 .auto_queue = false,
166                 .wake_capable = false,
167         },
168         {
169                 .name = "QAIC_QDSS",
170                 .num = 9,
171                 .num_elements = 32,
172                 .local_elements = 0,
173                 .event_ring = 0,
174                 .dir = DMA_FROM_DEVICE,
175                 .ee_mask = MHI_CH_EE_AMSS,
176                 .pollcfg = 0,
177                 .doorbell = MHI_DB_BRST_DISABLE,
178                 .lpm_notify = false,
179                 .offload_channel = false,
180                 .doorbell_mode_switch = false,
181                 .auto_queue = false,
182                 .wake_capable = false,
183         },
184         {
185                 .name = "QAIC_CONTROL",
186                 .num = 10,
187                 .num_elements = 128,
188                 .local_elements = 0,
189                 .event_ring = 0,
190                 .dir = DMA_TO_DEVICE,
191                 .ee_mask = MHI_CH_EE_AMSS,
192                 .pollcfg = 0,
193                 .doorbell = MHI_DB_BRST_DISABLE,
194                 .lpm_notify = false,
195                 .offload_channel = false,
196                 .doorbell_mode_switch = false,
197                 .auto_queue = false,
198                 .wake_capable = false,
199         },
200         {
201                 .name = "QAIC_CONTROL",
202                 .num = 11,
203                 .num_elements = 128,
204                 .local_elements = 0,
205                 .event_ring = 0,
206                 .dir = DMA_FROM_DEVICE,
207                 .ee_mask = MHI_CH_EE_AMSS,
208                 .pollcfg = 0,
209                 .doorbell = MHI_DB_BRST_DISABLE,
210                 .lpm_notify = false,
211                 .offload_channel = false,
212                 .doorbell_mode_switch = false,
213                 .auto_queue = false,
214                 .wake_capable = false,
215         },
216         {
217                 .name = "QAIC_LOGGING",
218                 .num = 12,
219                 .num_elements = 32,
220                 .local_elements = 0,
221                 .event_ring = 0,
222                 .dir = DMA_TO_DEVICE,
223                 .ee_mask = MHI_CH_EE_SBL,
224                 .pollcfg = 0,
225                 .doorbell = MHI_DB_BRST_DISABLE,
226                 .lpm_notify = false,
227                 .offload_channel = false,
228                 .doorbell_mode_switch = false,
229                 .auto_queue = false,
230                 .wake_capable = false,
231         },
232         {
233                 .name = "QAIC_LOGGING",
234                 .num = 13,
235                 .num_elements = 32,
236                 .local_elements = 0,
237                 .event_ring = 0,
238                 .dir = DMA_FROM_DEVICE,
239                 .ee_mask = MHI_CH_EE_SBL,
240                 .pollcfg = 0,
241                 .doorbell = MHI_DB_BRST_DISABLE,
242                 .lpm_notify = false,
243                 .offload_channel = false,
244                 .doorbell_mode_switch = false,
245                 .auto_queue = false,
246                 .wake_capable = false,
247         },
248         {
249                 .name = "QAIC_STATUS",
250                 .num = 14,
251                 .num_elements = 32,
252                 .local_elements = 0,
253                 .event_ring = 0,
254                 .dir = DMA_TO_DEVICE,
255                 .ee_mask = MHI_CH_EE_AMSS,
256                 .pollcfg = 0,
257                 .doorbell = MHI_DB_BRST_DISABLE,
258                 .lpm_notify = false,
259                 .offload_channel = false,
260                 .doorbell_mode_switch = false,
261                 .auto_queue = false,
262                 .wake_capable = false,
263         },
264         {
265                 .name = "QAIC_STATUS",
266                 .num = 15,
267                 .num_elements = 32,
268                 .local_elements = 0,
269                 .event_ring = 0,
270                 .dir = DMA_FROM_DEVICE,
271                 .ee_mask = MHI_CH_EE_AMSS,
272                 .pollcfg = 0,
273                 .doorbell = MHI_DB_BRST_DISABLE,
274                 .lpm_notify = false,
275                 .offload_channel = false,
276                 .doorbell_mode_switch = false,
277                 .auto_queue = false,
278                 .wake_capable = false,
279         },
280         {
281                 .name = "QAIC_TELEMETRY",
282                 .num = 16,
283                 .num_elements = 32,
284                 .local_elements = 0,
285                 .event_ring = 0,
286                 .dir = DMA_TO_DEVICE,
287                 .ee_mask = MHI_CH_EE_AMSS,
288                 .pollcfg = 0,
289                 .doorbell = MHI_DB_BRST_DISABLE,
290                 .lpm_notify = false,
291                 .offload_channel = false,
292                 .doorbell_mode_switch = false,
293                 .auto_queue = false,
294                 .wake_capable = false,
295         },
296         {
297                 .name = "QAIC_TELEMETRY",
298                 .num = 17,
299                 .num_elements = 32,
300                 .local_elements = 0,
301                 .event_ring = 0,
302                 .dir = DMA_FROM_DEVICE,
303                 .ee_mask = MHI_CH_EE_AMSS,
304                 .pollcfg = 0,
305                 .doorbell = MHI_DB_BRST_DISABLE,
306                 .lpm_notify = false,
307                 .offload_channel = false,
308                 .doorbell_mode_switch = false,
309                 .auto_queue = false,
310                 .wake_capable = false,
311         },
312         {
313                 .name = "QAIC_DEBUG",
314                 .num = 18,
315                 .num_elements = 32,
316                 .local_elements = 0,
317                 .event_ring = 0,
318                 .dir = DMA_TO_DEVICE,
319                 .ee_mask = MHI_CH_EE_AMSS,
320                 .pollcfg = 0,
321                 .doorbell = MHI_DB_BRST_DISABLE,
322                 .lpm_notify = false,
323                 .offload_channel = false,
324                 .doorbell_mode_switch = false,
325                 .auto_queue = false,
326                 .wake_capable = false,
327         },
328         {
329                 .name = "QAIC_DEBUG",
330                 .num = 19,
331                 .num_elements = 32,
332                 .local_elements = 0,
333                 .event_ring = 0,
334                 .dir = DMA_FROM_DEVICE,
335                 .ee_mask = MHI_CH_EE_AMSS,
336                 .pollcfg = 0,
337                 .doorbell = MHI_DB_BRST_DISABLE,
338                 .lpm_notify = false,
339                 .offload_channel = false,
340                 .doorbell_mode_switch = false,
341                 .auto_queue = false,
342                 .wake_capable = false,
343         },
344         {
345                 .name = "QAIC_TIMESYNC",
346                 .num = 20,
347                 .num_elements = 32,
348                 .local_elements = 0,
349                 .event_ring = 0,
350                 .dir = DMA_TO_DEVICE,
351                 .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS,
352                 .pollcfg = 0,
353                 .doorbell = MHI_DB_BRST_DISABLE,
354                 .lpm_notify = false,
355                 .offload_channel = false,
356                 .doorbell_mode_switch = false,
357                 .auto_queue = false,
358                 .wake_capable = false,
359         },
360         {
361                 .num = 21,
362                 .name = "QAIC_TIMESYNC",
363                 .num_elements = 32,
364                 .local_elements = 0,
365                 .event_ring = 0,
366                 .dir = DMA_FROM_DEVICE,
367                 .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS,
368                 .pollcfg = 0,
369                 .doorbell = MHI_DB_BRST_DISABLE,
370                 .lpm_notify = false,
371                 .offload_channel = false,
372                 .doorbell_mode_switch = false,
373                 .auto_queue = false,
374                 .wake_capable = false,
375         },
376 };
377
378 static struct mhi_event_config aic100_events[] = {
379         {
380                 .num_elements = 32,
381                 .irq_moderation_ms = 0,
382                 .irq = 0,
383                 .channel = U32_MAX,
384                 .priority = 1,
385                 .mode = MHI_DB_BRST_DISABLE,
386                 .data_type = MHI_ER_CTRL,
387                 .hardware_event = false,
388                 .client_managed = false,
389                 .offload_channel = false,
390         },
391 };
392
393 static struct mhi_controller_config aic100_config = {
394         .max_channels = 128,
395         .timeout_ms = 0, /* controlled by mhi_timeout */
396         .buf_len = 0,
397         .num_channels = ARRAY_SIZE(aic100_channels),
398         .ch_cfg = aic100_channels,
399         .num_events = ARRAY_SIZE(aic100_events),
400         .event_cfg = aic100_events,
401         .use_bounce_buf = false,
402         .m2_no_db = false,
403 };
404
405 static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out)
406 {
407         u32 tmp = readl_relaxed(addr);
408
409         if (tmp == U32_MAX)
410                 return -EIO;
411
412         *out = tmp;
413
414         return 0;
415 }
416
417 static void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 val)
418 {
419         writel_relaxed(val, addr);
420 }
421
422 static int mhi_runtime_get(struct mhi_controller *mhi_cntrl)
423 {
424         return 0;
425 }
426
427 static void mhi_runtime_put(struct mhi_controller *mhi_cntrl)
428 {
429 }
430
431 static void mhi_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback reason)
432 {
433         struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_cntrl->cntrl_dev));
434
435         /* this event occurs in atomic context */
436         if (reason == MHI_CB_FATAL_ERROR)
437                 pci_err(qdev->pdev, "Fatal error received from device. Attempting to recover\n");
438         /* this event occurs in non-atomic context */
439         if (reason == MHI_CB_SYS_ERROR)
440                 qaic_dev_reset_clean_local_state(qdev, true);
441 }
442
443 static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl)
444 {
445         u8 time_sec = 1;
446         int current_ee;
447         int ret;
448
449         /* Reset the device to bring the device in PBL EE */
450         mhi_soc_reset(mhi_cntrl);
451
452         /*
453          * Keep checking the execution environment(EE) after every 1 second
454          * interval.
455          */
456         do {
457                 msleep(1000);
458                 current_ee = mhi_get_exec_env(mhi_cntrl);
459         } while (current_ee != MHI_EE_PBL && time_sec++ <= MAX_RESET_TIME_SEC);
460
461         /* If the device is in PBL EE retry power up */
462         if (current_ee == MHI_EE_PBL)
463                 ret = mhi_async_power_up(mhi_cntrl);
464         else
465                 ret = -EIO;
466
467         return ret;
468 }
469
470 struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar,
471                                                     int mhi_irq)
472 {
473         struct mhi_controller *mhi_cntrl;
474         int ret;
475
476         mhi_cntrl = devm_kzalloc(&pci_dev->dev, sizeof(*mhi_cntrl), GFP_KERNEL);
477         if (!mhi_cntrl)
478                 return ERR_PTR(-ENOMEM);
479
480         mhi_cntrl->cntrl_dev = &pci_dev->dev;
481
482         /*
483          * Covers the entire possible physical ram region. Remote side is
484          * going to calculate a size of this range, so subtract 1 to prevent
485          * rollover.
486          */
487         mhi_cntrl->iova_start = 0;
488         mhi_cntrl->iova_stop = PHYS_ADDR_MAX - 1;
489         mhi_cntrl->status_cb = mhi_status_cb;
490         mhi_cntrl->runtime_get = mhi_runtime_get;
491         mhi_cntrl->runtime_put = mhi_runtime_put;
492         mhi_cntrl->read_reg = mhi_read_reg;
493         mhi_cntrl->write_reg = mhi_write_reg;
494         mhi_cntrl->regs = mhi_bar;
495         mhi_cntrl->reg_len = SZ_4K;
496         mhi_cntrl->nr_irqs = 1;
497         mhi_cntrl->irq = devm_kmalloc(&pci_dev->dev, sizeof(*mhi_cntrl->irq), GFP_KERNEL);
498
499         if (!mhi_cntrl->irq)
500                 return ERR_PTR(-ENOMEM);
501
502         mhi_cntrl->irq[0] = mhi_irq;
503         mhi_cntrl->fw_image = "qcom/aic100/sbl.bin";
504
505         /* use latest configured timeout */
506         aic100_config.timeout_ms = mhi_timeout_ms;
507         ret = mhi_register_controller(mhi_cntrl, &aic100_config);
508         if (ret) {
509                 pci_err(pci_dev, "mhi_register_controller failed %d\n", ret);
510                 return ERR_PTR(ret);
511         }
512
513         ret = mhi_prepare_for_power_up(mhi_cntrl);
514         if (ret) {
515                 pci_err(pci_dev, "mhi_prepare_for_power_up failed %d\n", ret);
516                 goto prepare_power_up_fail;
517         }
518
519         ret = mhi_async_power_up(mhi_cntrl);
520         /*
521          * If EIO is returned it is possible that device is in SBL EE, which is
522          * undesired. SOC reset the device and try to power up again.
523          */
524         if (ret == -EIO && MHI_EE_SBL == mhi_get_exec_env(mhi_cntrl)) {
525                 pci_err(pci_dev, "Found device in SBL at MHI init. Attempting a reset.\n");
526                 ret = mhi_reset_and_async_power_up(mhi_cntrl);
527         }
528
529         if (ret) {
530                 pci_err(pci_dev, "mhi_async_power_up failed %d\n", ret);
531                 goto power_up_fail;
532         }
533
534         return mhi_cntrl;
535
536 power_up_fail:
537         mhi_unprepare_after_power_down(mhi_cntrl);
538 prepare_power_up_fail:
539         mhi_unregister_controller(mhi_cntrl);
540         return ERR_PTR(ret);
541 }
542
543 void qaic_mhi_free_controller(struct mhi_controller *mhi_cntrl, bool link_up)
544 {
545         mhi_power_down(mhi_cntrl, link_up);
546         mhi_unprepare_after_power_down(mhi_cntrl);
547         mhi_unregister_controller(mhi_cntrl);
548 }
549
550 void qaic_mhi_start_reset(struct mhi_controller *mhi_cntrl)
551 {
552         mhi_power_down(mhi_cntrl, true);
553 }
554
555 void qaic_mhi_reset_done(struct mhi_controller *mhi_cntrl)
556 {
557         struct pci_dev *pci_dev = container_of(mhi_cntrl->cntrl_dev, struct pci_dev, dev);
558         int ret;
559
560         ret = mhi_async_power_up(mhi_cntrl);
561         if (ret)
562                 pci_err(pci_dev, "mhi_async_power_up failed after reset %d\n", ret);
563 }
This page took 0.065985 seconds and 4 git commands to generate.