]> Git Repo - J-linux.git/blob - drivers/misc/mei/platform-vsc.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / misc / mei / platform-vsc.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2023, Intel Corporation.
4  * Intel Visual Sensing Controller Interface Linux driver
5  */
6
7 #include <linux/align.h>
8 #include <linux/cache.h>
9 #include <linux/cleanup.h>
10 #include <linux/iopoll.h>
11 #include <linux/list.h>
12 #include <linux/mei.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/overflow.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/timekeeping.h>
19 #include <linux/types.h>
20
21 #include <asm-generic/bug.h>
22 #include <linux/unaligned.h>
23
24 #include "mei_dev.h"
25 #include "vsc-tp.h"
26
27 #define MEI_VSC_DRV_NAME                "intel_vsc"
28
29 #define MEI_VSC_MAX_MSG_SIZE            512
30
31 #define MEI_VSC_POLL_DELAY_US           (100 * USEC_PER_MSEC)
32 #define MEI_VSC_POLL_TIMEOUT_US         (400 * USEC_PER_MSEC)
33
34 #define mei_dev_to_vsc_hw(dev)          ((struct mei_vsc_hw *)((dev)->hw))
35
36 struct mei_vsc_host_timestamp {
37         u64 realtime;
38         u64 boottime;
39 };
40
41 struct mei_vsc_hw {
42         struct vsc_tp *tp;
43
44         bool fw_ready;
45         bool host_ready;
46
47         atomic_t write_lock_cnt;
48
49         u32 rx_len;
50         u32 rx_hdr;
51
52         /* buffer for tx */
53         char tx_buf[MEI_VSC_MAX_MSG_SIZE + sizeof(struct mei_msg_hdr)] ____cacheline_aligned;
54         /* buffer for rx */
55         char rx_buf[MEI_VSC_MAX_MSG_SIZE + sizeof(struct mei_msg_hdr)] ____cacheline_aligned;
56 };
57
58 static int mei_vsc_read_helper(struct mei_vsc_hw *hw, u8 *buf,
59                                u32 max_len)
60 {
61         struct mei_vsc_host_timestamp ts = {
62                 .realtime = ktime_to_ns(ktime_get_real()),
63                 .boottime = ktime_to_ns(ktime_get_boottime()),
64         };
65
66         return vsc_tp_xfer(hw->tp, VSC_TP_CMD_READ, &ts, sizeof(ts),
67                            buf, max_len);
68 }
69
70 static int mei_vsc_write_helper(struct mei_vsc_hw *hw, u8 *buf, u32 len)
71 {
72         u8 status;
73
74         return vsc_tp_xfer(hw->tp, VSC_TP_CMD_WRITE, buf, len, &status,
75                            sizeof(status));
76 }
77
78 static int mei_vsc_fw_status(struct mei_device *mei_dev,
79                              struct mei_fw_status *fw_status)
80 {
81         if (!fw_status)
82                 return -EINVAL;
83
84         fw_status->count = 0;
85
86         return 0;
87 }
88
89 static inline enum mei_pg_state mei_vsc_pg_state(struct mei_device *mei_dev)
90 {
91         return MEI_PG_OFF;
92 }
93
94 static void mei_vsc_intr_enable(struct mei_device *mei_dev)
95 {
96         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
97
98         vsc_tp_intr_enable(hw->tp);
99 }
100
101 static void mei_vsc_intr_disable(struct mei_device *mei_dev)
102 {
103         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
104
105         vsc_tp_intr_disable(hw->tp);
106 }
107
108 /* mei framework requires this ops */
109 static void mei_vsc_intr_clear(struct mei_device *mei_dev)
110 {
111 }
112
113 /* wait for pending irq handler */
114 static void mei_vsc_synchronize_irq(struct mei_device *mei_dev)
115 {
116         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
117
118         vsc_tp_intr_synchronize(hw->tp);
119 }
120
121 static int mei_vsc_hw_config(struct mei_device *mei_dev)
122 {
123         return 0;
124 }
125
126 static bool mei_vsc_host_is_ready(struct mei_device *mei_dev)
127 {
128         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
129
130         return hw->host_ready;
131 }
132
133 static bool mei_vsc_hw_is_ready(struct mei_device *mei_dev)
134 {
135         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
136
137         return hw->fw_ready;
138 }
139
140 static int mei_vsc_hw_start(struct mei_device *mei_dev)
141 {
142         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
143         int ret, rlen;
144         u8 buf;
145
146         hw->host_ready = true;
147
148         vsc_tp_intr_enable(hw->tp);
149
150         ret = read_poll_timeout(mei_vsc_read_helper, rlen,
151                                 rlen >= 0, MEI_VSC_POLL_DELAY_US,
152                                 MEI_VSC_POLL_TIMEOUT_US, true,
153                                 hw, &buf, sizeof(buf));
154         if (ret) {
155                 dev_err(mei_dev->dev, "wait fw ready failed: %d\n", ret);
156                 return ret;
157         }
158
159         hw->fw_ready = true;
160
161         return 0;
162 }
163
164 static bool mei_vsc_hbuf_is_ready(struct mei_device *mei_dev)
165 {
166         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
167
168         return atomic_read(&hw->write_lock_cnt) == 0;
169 }
170
171 static int mei_vsc_hbuf_empty_slots(struct mei_device *mei_dev)
172 {
173         return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
174 }
175
176 static u32 mei_vsc_hbuf_depth(const struct mei_device *mei_dev)
177 {
178         return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
179 }
180
181 static int mei_vsc_write(struct mei_device *mei_dev,
182                          const void *hdr, size_t hdr_len,
183                          const void *data, size_t data_len)
184 {
185         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
186         char *buf = hw->tx_buf;
187         int ret;
188
189         if (WARN_ON(!hdr || !IS_ALIGNED(hdr_len, 4)))
190                 return -EINVAL;
191
192         if (!data || data_len > MEI_VSC_MAX_MSG_SIZE)
193                 return -EINVAL;
194
195         atomic_inc(&hw->write_lock_cnt);
196
197         memcpy(buf, hdr, hdr_len);
198         memcpy(buf + hdr_len, data, data_len);
199
200         ret = mei_vsc_write_helper(hw, buf, hdr_len + data_len);
201
202         atomic_dec_if_positive(&hw->write_lock_cnt);
203
204         return ret < 0 ? ret : 0;
205 }
206
207 static inline u32 mei_vsc_read(const struct mei_device *mei_dev)
208 {
209         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
210         int ret;
211
212         ret = mei_vsc_read_helper(hw, hw->rx_buf, sizeof(hw->rx_buf));
213         if (ret < 0 || ret < sizeof(u32))
214                 return 0;
215         hw->rx_len = ret;
216
217         hw->rx_hdr = get_unaligned_le32(hw->rx_buf);
218
219         return hw->rx_hdr;
220 }
221
222 static int mei_vsc_count_full_read_slots(struct mei_device *mei_dev)
223 {
224         return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
225 }
226
227 static int mei_vsc_read_slots(struct mei_device *mei_dev, unsigned char *buf,
228                               unsigned long len)
229 {
230         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
231         struct mei_msg_hdr *hdr;
232
233         hdr = (struct mei_msg_hdr *)&hw->rx_hdr;
234         if (len != hdr->length || hdr->length + sizeof(*hdr) != hw->rx_len)
235                 return -EINVAL;
236
237         memcpy(buf, hw->rx_buf + sizeof(*hdr), len);
238
239         return 0;
240 }
241
242 static bool mei_vsc_pg_in_transition(struct mei_device *mei_dev)
243 {
244         return mei_dev->pg_event >= MEI_PG_EVENT_WAIT &&
245                mei_dev->pg_event <= MEI_PG_EVENT_INTR_WAIT;
246 }
247
248 static bool mei_vsc_pg_is_enabled(struct mei_device *mei_dev)
249 {
250         return false;
251 }
252
253 static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable)
254 {
255         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
256
257         vsc_tp_reset(hw->tp);
258
259         return vsc_tp_init(hw->tp, mei_dev->dev);
260 }
261
262 static const struct mei_hw_ops mei_vsc_hw_ops = {
263         .fw_status = mei_vsc_fw_status,
264         .pg_state = mei_vsc_pg_state,
265
266         .host_is_ready = mei_vsc_host_is_ready,
267         .hw_is_ready = mei_vsc_hw_is_ready,
268         .hw_reset = mei_vsc_hw_reset,
269         .hw_config = mei_vsc_hw_config,
270         .hw_start = mei_vsc_hw_start,
271
272         .pg_in_transition = mei_vsc_pg_in_transition,
273         .pg_is_enabled = mei_vsc_pg_is_enabled,
274
275         .intr_clear = mei_vsc_intr_clear,
276         .intr_enable = mei_vsc_intr_enable,
277         .intr_disable = mei_vsc_intr_disable,
278         .synchronize_irq = mei_vsc_synchronize_irq,
279
280         .hbuf_free_slots = mei_vsc_hbuf_empty_slots,
281         .hbuf_is_ready = mei_vsc_hbuf_is_ready,
282         .hbuf_depth = mei_vsc_hbuf_depth,
283         .write = mei_vsc_write,
284
285         .rdbuf_full_slots = mei_vsc_count_full_read_slots,
286         .read_hdr = mei_vsc_read,
287         .read = mei_vsc_read_slots,
288 };
289
290 static void mei_vsc_event_cb(void *context)
291 {
292         struct mei_device *mei_dev = context;
293         struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
294         struct list_head cmpl_list;
295         s32 slots;
296         int ret;
297
298         if (mei_dev->dev_state == MEI_DEV_RESETTING ||
299             mei_dev->dev_state == MEI_DEV_INITIALIZING)
300                 return;
301
302         INIT_LIST_HEAD(&cmpl_list);
303
304         guard(mutex)(&mei_dev->device_lock);
305
306         while (vsc_tp_need_read(hw->tp)) {
307                 /* check slots available for reading */
308                 slots = mei_count_full_read_slots(mei_dev);
309
310                 ret = mei_irq_read_handler(mei_dev, &cmpl_list, &slots);
311                 if (ret) {
312                         if (ret != -ENODATA) {
313                                 if (mei_dev->dev_state != MEI_DEV_RESETTING &&
314                                     mei_dev->dev_state != MEI_DEV_POWER_DOWN)
315                                         schedule_work(&mei_dev->reset_work);
316                         }
317
318                         return;
319                 }
320         }
321
322         mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev);
323         ret = mei_irq_write_handler(mei_dev, &cmpl_list);
324         if (ret)
325                 dev_err(mei_dev->dev, "dispatch write request failed: %d\n", ret);
326
327         mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev);
328         mei_irq_compl_handler(mei_dev, &cmpl_list);
329 }
330
331 static int mei_vsc_probe(struct platform_device *pdev)
332 {
333         struct device *dev = &pdev->dev;
334         struct mei_device *mei_dev;
335         struct mei_vsc_hw *hw;
336         struct vsc_tp *tp;
337         int ret;
338
339         tp = *(struct vsc_tp **)dev_get_platdata(dev);
340         if (!tp)
341                 return dev_err_probe(dev, -ENODEV, "no platform data\n");
342
343         mei_dev = devm_kzalloc(dev, size_add(sizeof(*mei_dev), sizeof(*hw)),
344                                GFP_KERNEL);
345         if (!mei_dev)
346                 return -ENOMEM;
347
348         mei_device_init(mei_dev, dev, false, &mei_vsc_hw_ops);
349         mei_dev->fw_f_fw_ver_supported = 0;
350         mei_dev->kind = "ivsc";
351
352         hw = mei_dev_to_vsc_hw(mei_dev);
353         atomic_set(&hw->write_lock_cnt, 0);
354         hw->tp = tp;
355
356         platform_set_drvdata(pdev, mei_dev);
357
358         vsc_tp_register_event_cb(tp, mei_vsc_event_cb, mei_dev);
359
360         ret = mei_start(mei_dev);
361         if (ret) {
362                 dev_err_probe(dev, ret, "init hw failed\n");
363                 goto err_cancel;
364         }
365
366         ret = mei_register(mei_dev, dev);
367         if (ret)
368                 goto err_stop;
369
370         pm_runtime_enable(mei_dev->dev);
371
372         return 0;
373
374 err_stop:
375         mei_stop(mei_dev);
376
377 err_cancel:
378         mei_cancel_work(mei_dev);
379
380         mei_disable_interrupts(mei_dev);
381
382         return ret;
383 }
384
385 static void mei_vsc_remove(struct platform_device *pdev)
386 {
387         struct mei_device *mei_dev = platform_get_drvdata(pdev);
388
389         pm_runtime_disable(mei_dev->dev);
390
391         mei_stop(mei_dev);
392
393         mei_disable_interrupts(mei_dev);
394
395         mei_deregister(mei_dev);
396 }
397
398 static int mei_vsc_suspend(struct device *dev)
399 {
400         struct mei_device *mei_dev;
401         int ret = 0;
402
403         mei_dev = dev_get_drvdata(dev);
404         if (!mei_dev)
405                 return -ENODEV;
406
407         mutex_lock(&mei_dev->device_lock);
408
409         if (!mei_write_is_idle(mei_dev))
410                 ret = -EAGAIN;
411
412         mutex_unlock(&mei_dev->device_lock);
413
414         return ret;
415 }
416
417 static int mei_vsc_resume(struct device *dev)
418 {
419         struct mei_device *mei_dev;
420
421         mei_dev = dev_get_drvdata(dev);
422         if (!mei_dev)
423                 return -ENODEV;
424
425         return 0;
426 }
427
428 static DEFINE_SIMPLE_DEV_PM_OPS(mei_vsc_pm_ops, mei_vsc_suspend, mei_vsc_resume);
429
430 static const struct platform_device_id mei_vsc_id_table[] = {
431         { MEI_VSC_DRV_NAME },
432         { /* sentinel */ }
433 };
434 MODULE_DEVICE_TABLE(platform, mei_vsc_id_table);
435
436 static struct platform_driver mei_vsc_drv = {
437         .probe = mei_vsc_probe,
438         .remove = mei_vsc_remove,
439         .id_table = mei_vsc_id_table,
440         .driver = {
441                 .name = MEI_VSC_DRV_NAME,
442                 .pm = &mei_vsc_pm_ops,
443                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
444         },
445 };
446 module_platform_driver(mei_vsc_drv);
447
448 MODULE_AUTHOR("Wentong Wu <[email protected]>");
449 MODULE_AUTHOR("Zhifeng Wang <[email protected]>");
450 MODULE_DESCRIPTION("Intel Visual Sensing Controller Interface");
451 MODULE_LICENSE("GPL");
452 MODULE_IMPORT_NS("VSC_TP");
This page took 0.050883 seconds and 4 git commands to generate.