blob: 275150338b9a2d03e3d54a3539e9852f2598b93c [file] [log] [blame]
Loic Poulain855a70c2020-10-21 19:18:19 +02001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * MHI PCI driver - MHI over PCI controller driver
4 *
5 * This module is a generic driver for registering MHI-over-PCI devices,
6 * such as PCIe QCOM modems.
7 *
8 * Copyright (C) 2020 Linaro Ltd <loic.poulain@linaro.org>
9 */
10
Loic Poulainb012ee62021-01-04 17:14:55 +010011#include <linux/aer.h>
Loic Poulain8ccc3272021-01-04 17:14:53 +010012#include <linux/delay.h>
Loic Poulain855a70c2020-10-21 19:18:19 +020013#include <linux/device.h>
14#include <linux/mhi.h>
15#include <linux/module.h>
16#include <linux/pci.h>
Loic Poulain8562d4f2021-01-04 17:14:56 +010017#include <linux/timer.h>
Loic Poulain73893372021-01-04 17:14:54 +010018#include <linux/workqueue.h>
Loic Poulain855a70c2020-10-21 19:18:19 +020019
20#define MHI_PCI_DEFAULT_BAR_NUM 0
21
Loic Poulain8ccc3272021-01-04 17:14:53 +010022#define MHI_POST_RESET_DELAY_MS 500
Loic Poulain8562d4f2021-01-04 17:14:56 +010023
24#define HEALTH_CHECK_PERIOD (HZ * 2)
25
Loic Poulain855a70c2020-10-21 19:18:19 +020026/**
27 * struct mhi_pci_dev_info - MHI PCI device specific information
28 * @config: MHI controller configuration
29 * @name: name of the PCI module
30 * @fw: firmware path (if any)
31 * @edl: emergency download mode firmware path (if any)
32 * @bar_num: PCI base address register to use for MHI MMIO register space
33 * @dma_data_width: DMA transfer word size (32 or 64 bits)
34 */
35struct mhi_pci_dev_info {
36 const struct mhi_controller_config *config;
37 const char *name;
38 const char *fw;
39 const char *edl;
40 unsigned int bar_num;
41 unsigned int dma_data_width;
42};
43
44#define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \
45 { \
46 .num = ch_num, \
47 .name = ch_name, \
48 .num_elements = el_count, \
49 .event_ring = ev_ring, \
50 .dir = DMA_TO_DEVICE, \
51 .ee_mask = BIT(MHI_EE_AMSS), \
52 .pollcfg = 0, \
53 .doorbell = MHI_DB_BRST_DISABLE, \
54 .lpm_notify = false, \
55 .offload_channel = false, \
56 .doorbell_mode_switch = false, \
57 } \
58
59#define MHI_CHANNEL_CONFIG_DL(ch_num, ch_name, el_count, ev_ring) \
60 { \
61 .num = ch_num, \
62 .name = ch_name, \
63 .num_elements = el_count, \
64 .event_ring = ev_ring, \
65 .dir = DMA_FROM_DEVICE, \
66 .ee_mask = BIT(MHI_EE_AMSS), \
67 .pollcfg = 0, \
68 .doorbell = MHI_DB_BRST_DISABLE, \
69 .lpm_notify = false, \
70 .offload_channel = false, \
71 .doorbell_mode_switch = false, \
72 }
73
Loic Poulain9ea48ef2021-03-05 20:16:43 +010074#define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \
Loic Poulain855a70c2020-10-21 19:18:19 +020075 { \
Loic Poulain9ea48ef2021-03-05 20:16:43 +010076 .num_elements = el_count, \
Loic Poulain855a70c2020-10-21 19:18:19 +020077 .irq_moderation_ms = 0, \
78 .irq = (ev_ring) + 1, \
79 .priority = 1, \
80 .mode = MHI_DB_BRST_DISABLE, \
81 .data_type = MHI_ER_CTRL, \
82 .hardware_event = false, \
83 .client_managed = false, \
84 .offload_channel = false, \
85 }
86
Loic Poulaineb967872021-01-04 17:14:52 +010087#define MHI_CHANNEL_CONFIG_HW_UL(ch_num, ch_name, el_count, ev_ring) \
88 { \
89 .num = ch_num, \
90 .name = ch_name, \
91 .num_elements = el_count, \
92 .event_ring = ev_ring, \
93 .dir = DMA_TO_DEVICE, \
94 .ee_mask = BIT(MHI_EE_AMSS), \
95 .pollcfg = 0, \
96 .doorbell = MHI_DB_BRST_ENABLE, \
97 .lpm_notify = false, \
98 .offload_channel = false, \
99 .doorbell_mode_switch = true, \
100 } \
101
102#define MHI_CHANNEL_CONFIG_HW_DL(ch_num, ch_name, el_count, ev_ring) \
103 { \
104 .num = ch_num, \
105 .name = ch_name, \
106 .num_elements = el_count, \
107 .event_ring = ev_ring, \
108 .dir = DMA_FROM_DEVICE, \
109 .ee_mask = BIT(MHI_EE_AMSS), \
110 .pollcfg = 0, \
111 .doorbell = MHI_DB_BRST_ENABLE, \
112 .lpm_notify = false, \
113 .offload_channel = false, \
114 .doorbell_mode_switch = true, \
115 }
116
Loic Poulainac4bf602021-03-05 20:16:44 +0100117#define MHI_CHANNEL_CONFIG_UL_SBL(ch_num, ch_name, el_count, ev_ring) \
118 { \
119 .num = ch_num, \
120 .name = ch_name, \
121 .num_elements = el_count, \
122 .event_ring = ev_ring, \
123 .dir = DMA_TO_DEVICE, \
124 .ee_mask = BIT(MHI_EE_SBL), \
125 .pollcfg = 0, \
126 .doorbell = MHI_DB_BRST_DISABLE, \
127 .lpm_notify = false, \
128 .offload_channel = false, \
129 .doorbell_mode_switch = false, \
130 } \
131
132#define MHI_CHANNEL_CONFIG_DL_SBL(ch_num, ch_name, el_count, ev_ring) \
133 { \
134 .num = ch_num, \
135 .name = ch_name, \
136 .num_elements = el_count, \
137 .event_ring = ev_ring, \
138 .dir = DMA_FROM_DEVICE, \
139 .ee_mask = BIT(MHI_EE_SBL), \
140 .pollcfg = 0, \
141 .doorbell = MHI_DB_BRST_DISABLE, \
142 .lpm_notify = false, \
143 .offload_channel = false, \
144 .doorbell_mode_switch = false, \
145 }
146
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100147#define MHI_EVENT_CONFIG_DATA(ev_ring, el_count) \
Loic Poulain855a70c2020-10-21 19:18:19 +0200148 { \
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100149 .num_elements = el_count, \
Loic Poulain855a70c2020-10-21 19:18:19 +0200150 .irq_moderation_ms = 5, \
151 .irq = (ev_ring) + 1, \
152 .priority = 1, \
153 .mode = MHI_DB_BRST_DISABLE, \
154 .data_type = MHI_ER_DATA, \
155 .hardware_event = false, \
156 .client_managed = false, \
157 .offload_channel = false, \
158 }
159
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100160#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, el_count, ch_num) \
Loic Poulain855a70c2020-10-21 19:18:19 +0200161 { \
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100162 .num_elements = el_count, \
Loic Poulainec7513692021-01-04 17:14:59 +0100163 .irq_moderation_ms = 1, \
Loic Poulain855a70c2020-10-21 19:18:19 +0200164 .irq = (ev_ring) + 1, \
165 .priority = 1, \
166 .mode = MHI_DB_BRST_DISABLE, \
167 .data_type = MHI_ER_DATA, \
168 .hardware_event = true, \
169 .client_managed = false, \
170 .offload_channel = false, \
171 .channel = ch_num, \
172 }
173
174static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
Loic Poulain4da3d072021-01-04 17:14:58 +0100175 MHI_CHANNEL_CONFIG_UL(4, "DIAG", 16, 1),
176 MHI_CHANNEL_CONFIG_DL(5, "DIAG", 16, 1),
Loic Poulain855a70c2020-10-21 19:18:19 +0200177 MHI_CHANNEL_CONFIG_UL(12, "MBIM", 4, 0),
178 MHI_CHANNEL_CONFIG_DL(13, "MBIM", 4, 0),
179 MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
180 MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
181 MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
182 MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
Loic Poulain4da3d072021-01-04 17:14:58 +0100183 MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
184 MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
Loic Poulain855a70c2020-10-21 19:18:19 +0200185};
186
Loic Poulainb91c3b32021-01-05 17:44:36 +0100187static struct mhi_event_config modem_qcom_v1_mhi_events[] = {
Loic Poulain855a70c2020-10-21 19:18:19 +0200188 /* first ring is control+data ring */
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100189 MHI_EVENT_CONFIG_CTRL(0, 64),
Loic Poulain4da3d072021-01-04 17:14:58 +0100190 /* DIAG dedicated event ring */
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100191 MHI_EVENT_CONFIG_DATA(1, 128),
Loic Poulain855a70c2020-10-21 19:18:19 +0200192 /* Hardware channels request dedicated hardware event rings */
Loic Poulain9ea48ef2021-03-05 20:16:43 +0100193 MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
194 MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101)
Loic Poulain855a70c2020-10-21 19:18:19 +0200195};
196
Loic Poulainb91c3b32021-01-05 17:44:36 +0100197static struct mhi_controller_config modem_qcom_v1_mhiv_config = {
Loic Poulain855a70c2020-10-21 19:18:19 +0200198 .max_channels = 128,
Loic Poulain84026a52021-01-04 17:14:57 +0100199 .timeout_ms = 8000,
Loic Poulain855a70c2020-10-21 19:18:19 +0200200 .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
201 .ch_cfg = modem_qcom_v1_mhi_channels,
202 .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
203 .event_cfg = modem_qcom_v1_mhi_events,
204};
205
206static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = {
207 .name = "qcom-sdx55m",
208 .fw = "qcom/sdx55m/sbl1.mbn",
209 .edl = "qcom/sdx55m/edl.mbn",
210 .config = &modem_qcom_v1_mhiv_config,
211 .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
212 .dma_data_width = 32
213};
214
Loic Poulainac4bf602021-03-05 20:16:44 +0100215static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = {
216 MHI_CHANNEL_CONFIG_UL(0, "NMEA", 32, 0),
217 MHI_CHANNEL_CONFIG_DL(1, "NMEA", 32, 0),
218 MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
219 MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
220 MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1),
221 MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1),
222 MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
223 MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
224 MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
225 MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
226 MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
227 MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
228};
229
230static struct mhi_event_config mhi_quectel_em1xx_events[] = {
231 MHI_EVENT_CONFIG_CTRL(0, 128),
232 MHI_EVENT_CONFIG_DATA(1, 128),
233 MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
234 MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101)
235};
236
237static struct mhi_controller_config modem_quectel_em1xx_config = {
238 .max_channels = 128,
239 .timeout_ms = 20000,
240 .num_channels = ARRAY_SIZE(mhi_quectel_em1xx_channels),
241 .ch_cfg = mhi_quectel_em1xx_channels,
242 .num_events = ARRAY_SIZE(mhi_quectel_em1xx_events),
243 .event_cfg = mhi_quectel_em1xx_events,
244};
245
246static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = {
247 .name = "quectel-em1xx",
248 .edl = "qcom/prog_firehose_sdx24.mbn",
249 .config = &modem_quectel_em1xx_config,
250 .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
251 .dma_data_width = 32
252};
253
Loic Poulain855a70c2020-10-21 19:18:19 +0200254static const struct pci_device_id mhi_pci_id_table[] = {
255 { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
256 .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info },
Loic Poulainac4bf602021-03-05 20:16:44 +0100257 { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */
258 .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
259 { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */
260 .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
Loic Poulain855a70c2020-10-21 19:18:19 +0200261 { }
262};
263MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
264
Loic Poulain8ccc3272021-01-04 17:14:53 +0100265enum mhi_pci_device_status {
266 MHI_PCI_DEV_STARTED,
267};
268
269struct mhi_pci_device {
270 struct mhi_controller mhi_cntrl;
271 struct pci_saved_state *pci_state;
Loic Poulain73893372021-01-04 17:14:54 +0100272 struct work_struct recovery_work;
Loic Poulain8562d4f2021-01-04 17:14:56 +0100273 struct timer_list health_check_timer;
Loic Poulain8ccc3272021-01-04 17:14:53 +0100274 unsigned long status;
275};
276
Loic Poulain855a70c2020-10-21 19:18:19 +0200277static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl,
278 void __iomem *addr, u32 *out)
279{
280 *out = readl(addr);
281 return 0;
282}
283
284static void mhi_pci_write_reg(struct mhi_controller *mhi_cntrl,
285 void __iomem *addr, u32 val)
286{
287 writel(val, addr);
288}
289
290static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
291 enum mhi_callback cb)
292{
Loic Poulain1e2f29b2021-02-03 17:39:42 +0100293 struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
294
Loic Poulain855a70c2020-10-21 19:18:19 +0200295 /* Nothing to do for now */
Loic Poulain1e2f29b2021-02-03 17:39:42 +0100296 switch (cb) {
297 case MHI_CB_FATAL_ERROR:
298 case MHI_CB_SYS_ERROR:
299 dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb);
300 break;
301 default:
302 break;
303 }
Loic Poulain855a70c2020-10-21 19:18:19 +0200304}
305
Loic Poulain8ccc3272021-01-04 17:14:53 +0100306static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl)
307{
308 struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
309 u16 vendor = 0;
310
311 if (pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor))
312 return false;
313
314 if (vendor == (u16) ~0 || vendor == 0)
315 return false;
316
317 return true;
318}
319
Loic Poulain855a70c2020-10-21 19:18:19 +0200320static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
321 unsigned int bar_num, u64 dma_mask)
322{
323 struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
324 int err;
325
326 err = pci_assign_resource(pdev, bar_num);
327 if (err)
328 return err;
329
330 err = pcim_enable_device(pdev);
331 if (err) {
332 dev_err(&pdev->dev, "failed to enable pci device: %d\n", err);
333 return err;
334 }
335
336 err = pcim_iomap_regions(pdev, 1 << bar_num, pci_name(pdev));
337 if (err) {
338 dev_err(&pdev->dev, "failed to map pci region: %d\n", err);
339 return err;
340 }
341 mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num];
342
343 err = pci_set_dma_mask(pdev, dma_mask);
344 if (err) {
345 dev_err(&pdev->dev, "Cannot set proper DMA mask\n");
346 return err;
347 }
348
349 err = pci_set_consistent_dma_mask(pdev, dma_mask);
350 if (err) {
351 dev_err(&pdev->dev, "set consistent dma mask failed\n");
352 return err;
353 }
354
355 pci_set_master(pdev);
356
357 return 0;
358}
359
360static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl,
361 const struct mhi_controller_config *mhi_cntrl_config)
362{
363 struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
364 int nr_vectors, i;
365 int *irq;
366
367 /*
368 * Alloc one MSI vector for BHI + one vector per event ring, ideally...
369 * No explicit pci_free_irq_vectors required, done by pcim_release.
370 */
371 mhi_cntrl->nr_irqs = 1 + mhi_cntrl_config->num_events;
372
373 nr_vectors = pci_alloc_irq_vectors(pdev, 1, mhi_cntrl->nr_irqs, PCI_IRQ_MSI);
374 if (nr_vectors < 0) {
375 dev_err(&pdev->dev, "Error allocating MSI vectors %d\n",
376 nr_vectors);
377 return nr_vectors;
378 }
379
380 if (nr_vectors < mhi_cntrl->nr_irqs) {
Loic Poulainb91c3b32021-01-05 17:44:36 +0100381 dev_warn(&pdev->dev, "using shared MSI\n");
382
383 /* Patch msi vectors, use only one (shared) */
384 for (i = 0; i < mhi_cntrl_config->num_events; i++)
385 mhi_cntrl_config->event_cfg[i].irq = 0;
386 mhi_cntrl->nr_irqs = 1;
Loic Poulain855a70c2020-10-21 19:18:19 +0200387 }
388
389 irq = devm_kcalloc(&pdev->dev, mhi_cntrl->nr_irqs, sizeof(int), GFP_KERNEL);
390 if (!irq)
391 return -ENOMEM;
392
393 for (i = 0; i < mhi_cntrl->nr_irqs; i++) {
394 int vector = i >= nr_vectors ? (nr_vectors - 1) : i;
395
396 irq[i] = pci_irq_vector(pdev, vector);
397 }
398
399 mhi_cntrl->irq = irq;
400
401 return 0;
402}
403
404static int mhi_pci_runtime_get(struct mhi_controller *mhi_cntrl)
405{
406 /* no PM for now */
407 return 0;
408}
409
410static void mhi_pci_runtime_put(struct mhi_controller *mhi_cntrl)
411{
412 /* no PM for now */
413}
414
Loic Poulain73893372021-01-04 17:14:54 +0100415static void mhi_pci_recovery_work(struct work_struct *work)
416{
417 struct mhi_pci_device *mhi_pdev = container_of(work, struct mhi_pci_device,
418 recovery_work);
419 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
420 struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
421 int err;
422
423 dev_warn(&pdev->dev, "device recovery started\n");
424
Loic Poulain8562d4f2021-01-04 17:14:56 +0100425 del_timer(&mhi_pdev->health_check_timer);
426
Loic Poulain73893372021-01-04 17:14:54 +0100427 /* Clean up MHI state */
428 if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
429 mhi_power_down(mhi_cntrl, false);
430 mhi_unprepare_after_power_down(mhi_cntrl);
431 }
432
433 /* Check if we can recover without full reset */
434 pci_set_power_state(pdev, PCI_D0);
435 pci_load_saved_state(pdev, mhi_pdev->pci_state);
436 pci_restore_state(pdev);
437
438 if (!mhi_pci_is_alive(mhi_cntrl))
439 goto err_try_reset;
440
441 err = mhi_prepare_for_power_up(mhi_cntrl);
442 if (err)
443 goto err_try_reset;
444
445 err = mhi_sync_power_up(mhi_cntrl);
446 if (err)
447 goto err_unprepare;
448
449 dev_dbg(&pdev->dev, "Recovery completed\n");
450
451 set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
Loic Poulain8562d4f2021-01-04 17:14:56 +0100452 mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
Loic Poulain73893372021-01-04 17:14:54 +0100453 return;
454
455err_unprepare:
456 mhi_unprepare_after_power_down(mhi_cntrl);
457err_try_reset:
458 if (pci_reset_function(pdev))
459 dev_err(&pdev->dev, "Recovery failed\n");
460}
461
Loic Poulain8562d4f2021-01-04 17:14:56 +0100462static void health_check(struct timer_list *t)
463{
464 struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer);
465 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
466
467 if (!mhi_pci_is_alive(mhi_cntrl)) {
468 dev_err(mhi_cntrl->cntrl_dev, "Device died\n");
469 queue_work(system_long_wq, &mhi_pdev->recovery_work);
470 return;
471 }
472
473 /* reschedule in two seconds */
474 mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
475}
476
Loic Poulain855a70c2020-10-21 19:18:19 +0200477static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
478{
479 const struct mhi_pci_dev_info *info = (struct mhi_pci_dev_info *) id->driver_data;
480 const struct mhi_controller_config *mhi_cntrl_config;
Loic Poulain8ccc3272021-01-04 17:14:53 +0100481 struct mhi_pci_device *mhi_pdev;
Loic Poulain855a70c2020-10-21 19:18:19 +0200482 struct mhi_controller *mhi_cntrl;
483 int err;
484
485 dev_dbg(&pdev->dev, "MHI PCI device found: %s\n", info->name);
486
Loic Poulain8ccc3272021-01-04 17:14:53 +0100487 /* mhi_pdev.mhi_cntrl must be zero-initialized */
488 mhi_pdev = devm_kzalloc(&pdev->dev, sizeof(*mhi_pdev), GFP_KERNEL);
489 if (!mhi_pdev)
Loic Poulain855a70c2020-10-21 19:18:19 +0200490 return -ENOMEM;
491
Loic Poulain73893372021-01-04 17:14:54 +0100492 INIT_WORK(&mhi_pdev->recovery_work, mhi_pci_recovery_work);
Loic Poulain8562d4f2021-01-04 17:14:56 +0100493 timer_setup(&mhi_pdev->health_check_timer, health_check, 0);
Loic Poulain73893372021-01-04 17:14:54 +0100494
Loic Poulain855a70c2020-10-21 19:18:19 +0200495 mhi_cntrl_config = info->config;
Loic Poulain8ccc3272021-01-04 17:14:53 +0100496 mhi_cntrl = &mhi_pdev->mhi_cntrl;
497
Loic Poulain855a70c2020-10-21 19:18:19 +0200498 mhi_cntrl->cntrl_dev = &pdev->dev;
499 mhi_cntrl->iova_start = 0;
Loic Poulain4ea6fa22020-12-02 09:12:30 +0100500 mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(info->dma_data_width);
Loic Poulain855a70c2020-10-21 19:18:19 +0200501 mhi_cntrl->fw_image = info->fw;
502 mhi_cntrl->edl_image = info->edl;
503
504 mhi_cntrl->read_reg = mhi_pci_read_reg;
505 mhi_cntrl->write_reg = mhi_pci_write_reg;
506 mhi_cntrl->status_cb = mhi_pci_status_cb;
507 mhi_cntrl->runtime_get = mhi_pci_runtime_get;
508 mhi_cntrl->runtime_put = mhi_pci_runtime_put;
509
510 err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width));
511 if (err)
Loic Poulain8ccc3272021-01-04 17:14:53 +0100512 return err;
Loic Poulain855a70c2020-10-21 19:18:19 +0200513
514 err = mhi_pci_get_irqs(mhi_cntrl, mhi_cntrl_config);
515 if (err)
Loic Poulain8ccc3272021-01-04 17:14:53 +0100516 return err;
Loic Poulain855a70c2020-10-21 19:18:19 +0200517
Loic Poulain8ccc3272021-01-04 17:14:53 +0100518 pci_set_drvdata(pdev, mhi_pdev);
519
520 /* Have stored pci confspace at hand for restore in sudden PCI error */
521 pci_save_state(pdev);
522 mhi_pdev->pci_state = pci_store_saved_state(pdev);
Loic Poulain855a70c2020-10-21 19:18:19 +0200523
Loic Poulainb012ee62021-01-04 17:14:55 +0100524 pci_enable_pcie_error_reporting(pdev);
525
Loic Poulain855a70c2020-10-21 19:18:19 +0200526 err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config);
527 if (err)
Loic Poulain8ccc3272021-01-04 17:14:53 +0100528 return err;
Loic Poulain855a70c2020-10-21 19:18:19 +0200529
530 /* MHI bus does not power up the controller by default */
531 err = mhi_prepare_for_power_up(mhi_cntrl);
532 if (err) {
533 dev_err(&pdev->dev, "failed to prepare MHI controller\n");
534 goto err_unregister;
535 }
536
537 err = mhi_sync_power_up(mhi_cntrl);
538 if (err) {
539 dev_err(&pdev->dev, "failed to power up MHI controller\n");
540 goto err_unprepare;
541 }
542
Loic Poulain8ccc3272021-01-04 17:14:53 +0100543 set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
544
Loic Poulain8562d4f2021-01-04 17:14:56 +0100545 /* start health check */
546 mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
547
Loic Poulain855a70c2020-10-21 19:18:19 +0200548 return 0;
549
550err_unprepare:
551 mhi_unprepare_after_power_down(mhi_cntrl);
552err_unregister:
553 mhi_unregister_controller(mhi_cntrl);
Loic Poulain855a70c2020-10-21 19:18:19 +0200554
555 return err;
556}
557
558static void mhi_pci_remove(struct pci_dev *pdev)
559{
Loic Poulain8ccc3272021-01-04 17:14:53 +0100560 struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
561 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
Loic Poulain855a70c2020-10-21 19:18:19 +0200562
Loic Poulain8562d4f2021-01-04 17:14:56 +0100563 del_timer(&mhi_pdev->health_check_timer);
Loic Poulain73893372021-01-04 17:14:54 +0100564 cancel_work_sync(&mhi_pdev->recovery_work);
565
Loic Poulain8ccc3272021-01-04 17:14:53 +0100566 if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
567 mhi_power_down(mhi_cntrl, true);
568 mhi_unprepare_after_power_down(mhi_cntrl);
569 }
570
Loic Poulain855a70c2020-10-21 19:18:19 +0200571 mhi_unregister_controller(mhi_cntrl);
Loic Poulain855a70c2020-10-21 19:18:19 +0200572}
573
Loic Poulain8ccc3272021-01-04 17:14:53 +0100574static void mhi_pci_reset_prepare(struct pci_dev *pdev)
575{
576 struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
577 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
578
579 dev_info(&pdev->dev, "reset\n");
580
Loic Poulain8562d4f2021-01-04 17:14:56 +0100581 del_timer(&mhi_pdev->health_check_timer);
582
Loic Poulain8ccc3272021-01-04 17:14:53 +0100583 /* Clean up MHI state */
584 if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
585 mhi_power_down(mhi_cntrl, false);
586 mhi_unprepare_after_power_down(mhi_cntrl);
587 }
588
589 /* cause internal device reset */
590 mhi_soc_reset(mhi_cntrl);
591
592 /* Be sure device reset has been executed */
593 msleep(MHI_POST_RESET_DELAY_MS);
594}
595
596static void mhi_pci_reset_done(struct pci_dev *pdev)
597{
598 struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
599 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
600 int err;
601
602 /* Restore initial known working PCI state */
603 pci_load_saved_state(pdev, mhi_pdev->pci_state);
604 pci_restore_state(pdev);
605
606 /* Is device status available ? */
607 if (!mhi_pci_is_alive(mhi_cntrl)) {
608 dev_err(&pdev->dev, "reset failed\n");
609 return;
610 }
611
612 err = mhi_prepare_for_power_up(mhi_cntrl);
613 if (err) {
614 dev_err(&pdev->dev, "failed to prepare MHI controller\n");
615 return;
616 }
617
618 err = mhi_sync_power_up(mhi_cntrl);
619 if (err) {
620 dev_err(&pdev->dev, "failed to power up MHI controller\n");
621 mhi_unprepare_after_power_down(mhi_cntrl);
622 return;
623 }
624
625 set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
Loic Poulain8562d4f2021-01-04 17:14:56 +0100626 mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
Loic Poulain8ccc3272021-01-04 17:14:53 +0100627}
628
Loic Poulainb012ee62021-01-04 17:14:55 +0100629static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev,
630 pci_channel_state_t state)
631{
632 struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
633 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
634
635 dev_err(&pdev->dev, "PCI error detected, state = %u\n", state);
636
637 if (state == pci_channel_io_perm_failure)
638 return PCI_ERS_RESULT_DISCONNECT;
639
640 /* Clean up MHI state */
641 if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
642 mhi_power_down(mhi_cntrl, false);
643 mhi_unprepare_after_power_down(mhi_cntrl);
644 } else {
645 /* Nothing to do */
646 return PCI_ERS_RESULT_RECOVERED;
647 }
648
649 pci_disable_device(pdev);
650
651 return PCI_ERS_RESULT_NEED_RESET;
652}
653
654static pci_ers_result_t mhi_pci_slot_reset(struct pci_dev *pdev)
655{
656 if (pci_enable_device(pdev)) {
657 dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n");
658 return PCI_ERS_RESULT_DISCONNECT;
659 }
660
661 return PCI_ERS_RESULT_RECOVERED;
662}
663
664static void mhi_pci_io_resume(struct pci_dev *pdev)
665{
666 struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
667
668 dev_err(&pdev->dev, "PCI slot reset done\n");
669
670 queue_work(system_long_wq, &mhi_pdev->recovery_work);
671}
672
Loic Poulain8ccc3272021-01-04 17:14:53 +0100673static const struct pci_error_handlers mhi_pci_err_handler = {
Loic Poulainb012ee62021-01-04 17:14:55 +0100674 .error_detected = mhi_pci_error_detected,
675 .slot_reset = mhi_pci_slot_reset,
676 .resume = mhi_pci_io_resume,
Loic Poulain8ccc3272021-01-04 17:14:53 +0100677 .reset_prepare = mhi_pci_reset_prepare,
678 .reset_done = mhi_pci_reset_done,
679};
680
Loic Poulain73893372021-01-04 17:14:54 +0100681static int __maybe_unused mhi_pci_suspend(struct device *dev)
682{
683 struct pci_dev *pdev = to_pci_dev(dev);
684 struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
685 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
686
Loic Poulain8562d4f2021-01-04 17:14:56 +0100687 del_timer(&mhi_pdev->health_check_timer);
Loic Poulain73893372021-01-04 17:14:54 +0100688 cancel_work_sync(&mhi_pdev->recovery_work);
689
690 /* Transition to M3 state */
691 mhi_pm_suspend(mhi_cntrl);
692
693 pci_save_state(pdev);
694 pci_disable_device(pdev);
695 pci_wake_from_d3(pdev, true);
696 pci_set_power_state(pdev, PCI_D3hot);
697
698 return 0;
699}
700
701static int __maybe_unused mhi_pci_resume(struct device *dev)
702{
703 struct pci_dev *pdev = to_pci_dev(dev);
704 struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
705 struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
706 int err;
707
708 pci_set_power_state(pdev, PCI_D0);
709 pci_restore_state(pdev);
710 pci_set_master(pdev);
711
712 err = pci_enable_device(pdev);
713 if (err)
714 goto err_recovery;
715
716 /* Exit M3, transition to M0 state */
717 err = mhi_pm_resume(mhi_cntrl);
718 if (err) {
719 dev_err(&pdev->dev, "failed to resume device: %d\n", err);
720 goto err_recovery;
721 }
722
Loic Poulain8562d4f2021-01-04 17:14:56 +0100723 /* Resume health check */
724 mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
725
Loic Poulain73893372021-01-04 17:14:54 +0100726 return 0;
727
728err_recovery:
729 /* The device may have loose power or crashed, try recovering it */
730 queue_work(system_long_wq, &mhi_pdev->recovery_work);
731
732 return err;
733}
734
735static const struct dev_pm_ops mhi_pci_pm_ops = {
736 SET_SYSTEM_SLEEP_PM_OPS(mhi_pci_suspend, mhi_pci_resume)
737};
738
Loic Poulain855a70c2020-10-21 19:18:19 +0200739static struct pci_driver mhi_pci_driver = {
740 .name = "mhi-pci-generic",
741 .id_table = mhi_pci_id_table,
742 .probe = mhi_pci_probe,
Loic Poulain8ccc3272021-01-04 17:14:53 +0100743 .remove = mhi_pci_remove,
744 .err_handler = &mhi_pci_err_handler,
Loic Poulain73893372021-01-04 17:14:54 +0100745 .driver.pm = &mhi_pci_pm_ops
Loic Poulain855a70c2020-10-21 19:18:19 +0200746};
747module_pci_driver(mhi_pci_driver);
748
749MODULE_AUTHOR("Loic Poulain <loic.poulain@linaro.org>");
750MODULE_DESCRIPTION("Modem Host Interface (MHI) PCI controller driver");
751MODULE_LICENSE("GPL");