Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hte/hte.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (c) 2021-2022 NVIDIA Corporation
4
*
5
* Author: Dipen Patel <[email protected]>
6
*/
7
8
#include <linux/kernel.h>
9
#include <linux/module.h>
10
#include <linux/err.h>
11
#include <linux/slab.h>
12
#include <linux/of.h>
13
#include <linux/mutex.h>
14
#include <linux/uaccess.h>
15
#include <linux/hte.h>
16
#include <linux/delay.h>
17
#include <linux/debugfs.h>
18
#include <linux/device.h>
19
20
/* Global list of the HTE devices */
21
static DEFINE_SPINLOCK(hte_lock);
22
static LIST_HEAD(hte_devices);
23
24
enum {
25
HTE_TS_REGISTERED,
26
HTE_TS_REQ,
27
HTE_TS_DISABLE,
28
HTE_TS_QUEUE_WK,
29
};
30
31
/**
32
* struct hte_ts_info - Information related to requested timestamp.
33
*
34
* @xlated_id: Timestamp ID as understood between HTE subsys and HTE provider,
35
* See xlate callback API.
36
* @flags: Flags holding state information.
37
* @hte_cb_flags: Callback related flags.
38
* @seq: Timestamp sequence counter.
39
* @line_name: HTE allocated line name.
40
* @free_attr_name: If set, free the attr name.
41
* @cb: A nonsleeping callback function provided by clients.
42
* @tcb: A secondary sleeping callback function provided by clients.
43
* @dropped_ts: Dropped timestamps.
44
* @slock: Spin lock to synchronize between disable/enable,
45
* request/release APIs.
46
* @cb_work: callback workqueue, used when tcb is specified.
47
* @req_mlock: Lock during timestamp request/release APIs.
48
* @ts_dbg_root: Root for the debug fs.
49
* @gdev: HTE abstract device that this timestamp information belongs to.
50
* @cl_data: Client specific data.
51
*/
52
struct hte_ts_info {
53
u32 xlated_id;
54
unsigned long flags;
55
unsigned long hte_cb_flags;
56
u64 seq;
57
char *line_name;
58
bool free_attr_name;
59
hte_ts_cb_t cb;
60
hte_ts_sec_cb_t tcb;
61
atomic_t dropped_ts;
62
spinlock_t slock;
63
struct work_struct cb_work;
64
struct mutex req_mlock;
65
struct dentry *ts_dbg_root;
66
struct hte_device *gdev;
67
void *cl_data;
68
};
69
70
/**
71
* struct hte_device - HTE abstract device
72
* @nlines: Number of entities this device supports.
73
* @ts_req: Total number of entities requested.
74
* @sdev: Device used at various debug prints.
75
* @dbg_root: Root directory for debug fs.
76
* @list: List node to store hte_device for each provider.
77
* @chip: HTE chip providing this HTE device.
78
* @owner: helps prevent removal of modules when in use.
79
* @ei: Timestamp information.
80
*/
81
struct hte_device {
82
u32 nlines;
83
atomic_t ts_req;
84
struct device *sdev;
85
struct dentry *dbg_root;
86
struct list_head list;
87
struct hte_chip *chip;
88
struct module *owner;
89
struct hte_ts_info ei[] __counted_by(nlines);
90
};
91
92
#ifdef CONFIG_DEBUG_FS
93
94
static struct dentry *hte_root;
95
96
static int __init hte_subsys_dbgfs_init(void)
97
{
98
/* creates /sys/kernel/debug/hte/ */
99
hte_root = debugfs_create_dir("hte", NULL);
100
101
return 0;
102
}
103
subsys_initcall(hte_subsys_dbgfs_init);
104
105
static void hte_chip_dbgfs_init(struct hte_device *gdev)
106
{
107
const struct hte_chip *chip = gdev->chip;
108
const char *name = chip->name ? chip->name : dev_name(chip->dev);
109
110
gdev->dbg_root = debugfs_create_dir(name, hte_root);
111
112
debugfs_create_atomic_t("ts_requested", 0444, gdev->dbg_root,
113
&gdev->ts_req);
114
debugfs_create_u32("total_ts", 0444, gdev->dbg_root,
115
&gdev->nlines);
116
}
117
118
static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
119
{
120
if (!ei->gdev->dbg_root || !name)
121
return;
122
123
ei->ts_dbg_root = debugfs_create_dir(name, ei->gdev->dbg_root);
124
125
debugfs_create_atomic_t("dropped_timestamps", 0444, ei->ts_dbg_root,
126
&ei->dropped_ts);
127
}
128
129
#else
130
131
static void hte_chip_dbgfs_init(struct hte_device *gdev)
132
{
133
}
134
135
static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)
136
{
137
}
138
139
#endif
140
141
/**
142
* hte_ts_put() - Release and disable timestamp for the given desc.
143
*
144
* @desc: timestamp descriptor.
145
*
146
* Context: debugfs_remove_recursive() function call may use sleeping locks,
147
* not suitable from atomic context.
148
* Returns: 0 on success or a negative error code on failure.
149
*/
150
int hte_ts_put(struct hte_ts_desc *desc)
151
{
152
int ret = 0;
153
unsigned long flag;
154
struct hte_device *gdev;
155
struct hte_ts_info *ei;
156
157
if (!desc)
158
return -EINVAL;
159
160
ei = desc->hte_data;
161
162
if (!ei || !ei->gdev)
163
return -EINVAL;
164
165
gdev = ei->gdev;
166
167
mutex_lock(&ei->req_mlock);
168
169
if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
170
!test_bit(HTE_TS_REGISTERED, &ei->flags))) {
171
dev_info(gdev->sdev, "id:%d is not requested\n",
172
desc->attr.line_id);
173
ret = -EINVAL;
174
goto unlock;
175
}
176
177
if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&
178
test_bit(HTE_TS_REGISTERED, &ei->flags))) {
179
dev_info(gdev->sdev, "id:%d is registered but not requested\n",
180
desc->attr.line_id);
181
ret = -EINVAL;
182
goto unlock;
183
}
184
185
if (test_bit(HTE_TS_REQ, &ei->flags) &&
186
!test_bit(HTE_TS_REGISTERED, &ei->flags)) {
187
clear_bit(HTE_TS_REQ, &ei->flags);
188
desc->hte_data = NULL;
189
ret = 0;
190
goto mod_put;
191
}
192
193
ret = gdev->chip->ops->release(gdev->chip, desc, ei->xlated_id);
194
if (ret) {
195
dev_err(gdev->sdev, "id: %d free failed\n",
196
desc->attr.line_id);
197
goto unlock;
198
}
199
200
kfree(ei->line_name);
201
if (ei->free_attr_name)
202
kfree_const(desc->attr.name);
203
204
debugfs_remove_recursive(ei->ts_dbg_root);
205
206
spin_lock_irqsave(&ei->slock, flag);
207
208
if (test_bit(HTE_TS_QUEUE_WK, &ei->flags)) {
209
spin_unlock_irqrestore(&ei->slock, flag);
210
flush_work(&ei->cb_work);
211
spin_lock_irqsave(&ei->slock, flag);
212
}
213
214
atomic_dec(&gdev->ts_req);
215
atomic_set(&ei->dropped_ts, 0);
216
217
ei->seq = 1;
218
ei->flags = 0;
219
desc->hte_data = NULL;
220
221
spin_unlock_irqrestore(&ei->slock, flag);
222
223
ei->cb = NULL;
224
ei->tcb = NULL;
225
ei->cl_data = NULL;
226
227
mod_put:
228
module_put(gdev->owner);
229
unlock:
230
mutex_unlock(&ei->req_mlock);
231
dev_dbg(gdev->sdev, "release id: %d\n", desc->attr.line_id);
232
233
return ret;
234
}
235
EXPORT_SYMBOL_GPL(hte_ts_put);
236
237
static int hte_ts_dis_en_common(struct hte_ts_desc *desc, bool en)
238
{
239
u32 ts_id;
240
struct hte_device *gdev;
241
struct hte_ts_info *ei;
242
int ret;
243
unsigned long flag;
244
245
if (!desc)
246
return -EINVAL;
247
248
ei = desc->hte_data;
249
250
if (!ei || !ei->gdev)
251
return -EINVAL;
252
253
gdev = ei->gdev;
254
ts_id = desc->attr.line_id;
255
256
mutex_lock(&ei->req_mlock);
257
258
if (!test_bit(HTE_TS_REGISTERED, &ei->flags)) {
259
dev_dbg(gdev->sdev, "id:%d is not registered", ts_id);
260
ret = -EUSERS;
261
goto out;
262
}
263
264
spin_lock_irqsave(&ei->slock, flag);
265
266
if (en) {
267
if (!test_bit(HTE_TS_DISABLE, &ei->flags)) {
268
ret = 0;
269
goto out_unlock;
270
}
271
272
spin_unlock_irqrestore(&ei->slock, flag);
273
ret = gdev->chip->ops->enable(gdev->chip, ei->xlated_id);
274
if (ret) {
275
dev_warn(gdev->sdev, "id: %d enable failed\n",
276
ts_id);
277
goto out;
278
}
279
280
spin_lock_irqsave(&ei->slock, flag);
281
clear_bit(HTE_TS_DISABLE, &ei->flags);
282
} else {
283
if (test_bit(HTE_TS_DISABLE, &ei->flags)) {
284
ret = 0;
285
goto out_unlock;
286
}
287
288
spin_unlock_irqrestore(&ei->slock, flag);
289
ret = gdev->chip->ops->disable(gdev->chip, ei->xlated_id);
290
if (ret) {
291
dev_warn(gdev->sdev, "id: %d disable failed\n",
292
ts_id);
293
goto out;
294
}
295
296
spin_lock_irqsave(&ei->slock, flag);
297
set_bit(HTE_TS_DISABLE, &ei->flags);
298
}
299
300
out_unlock:
301
spin_unlock_irqrestore(&ei->slock, flag);
302
out:
303
mutex_unlock(&ei->req_mlock);
304
return ret;
305
}
306
307
/**
308
* hte_disable_ts() - Disable timestamp on given descriptor.
309
*
310
* The API does not release any resources associated with desc.
311
*
312
* @desc: ts descriptor, this is the same as returned by the request API.
313
*
314
* Context: Holds mutex lock, not suitable from atomic context.
315
* Returns: 0 on success or a negative error code on failure.
316
*/
317
int hte_disable_ts(struct hte_ts_desc *desc)
318
{
319
return hte_ts_dis_en_common(desc, false);
320
}
321
EXPORT_SYMBOL_GPL(hte_disable_ts);
322
323
/**
324
* hte_enable_ts() - Enable timestamp on given descriptor.
325
*
326
* @desc: ts descriptor, this is the same as returned by the request API.
327
*
328
* Context: Holds mutex lock, not suitable from atomic context.
329
* Returns: 0 on success or a negative error code on failure.
330
*/
331
int hte_enable_ts(struct hte_ts_desc *desc)
332
{
333
return hte_ts_dis_en_common(desc, true);
334
}
335
EXPORT_SYMBOL_GPL(hte_enable_ts);
336
337
static void hte_do_cb_work(struct work_struct *w)
338
{
339
unsigned long flag;
340
struct hte_ts_info *ei = container_of(w, struct hte_ts_info, cb_work);
341
342
if (unlikely(!ei->tcb))
343
return;
344
345
ei->tcb(ei->cl_data);
346
347
spin_lock_irqsave(&ei->slock, flag);
348
clear_bit(HTE_TS_QUEUE_WK, &ei->flags);
349
spin_unlock_irqrestore(&ei->slock, flag);
350
}
351
352
static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb,
353
hte_ts_sec_cb_t tcb, void *data)
354
{
355
int ret;
356
struct hte_device *gdev;
357
struct hte_ts_info *ei = desc->hte_data;
358
359
gdev = ei->gdev;
360
/*
361
* There is a chance that multiple consumers requesting same entity,
362
* lock here.
363
*/
364
mutex_lock(&ei->req_mlock);
365
366
if (test_bit(HTE_TS_REGISTERED, &ei->flags) ||
367
!test_bit(HTE_TS_REQ, &ei->flags)) {
368
dev_dbg(gdev->chip->dev, "id:%u req failed\n",
369
desc->attr.line_id);
370
ret = -EUSERS;
371
goto unlock;
372
}
373
374
ei->cb = cb;
375
ei->tcb = tcb;
376
if (tcb)
377
INIT_WORK(&ei->cb_work, hte_do_cb_work);
378
379
ret = gdev->chip->ops->request(gdev->chip, desc, ei->xlated_id);
380
if (ret < 0) {
381
dev_err(gdev->chip->dev, "ts request failed\n");
382
goto unlock;
383
}
384
385
ei->cl_data = data;
386
ei->seq = 1;
387
388
atomic_inc(&gdev->ts_req);
389
390
if (desc->attr.name)
391
ei->line_name = NULL;
392
else
393
ei->line_name = kasprintf(GFP_KERNEL, "ts_%u", desc->attr.line_id);
394
395
hte_ts_dbgfs_init(desc->attr.name == NULL ?
396
ei->line_name : desc->attr.name, ei);
397
set_bit(HTE_TS_REGISTERED, &ei->flags);
398
399
dev_dbg(gdev->chip->dev, "id: %u, xlated id:%u",
400
desc->attr.line_id, ei->xlated_id);
401
402
ret = 0;
403
404
unlock:
405
mutex_unlock(&ei->req_mlock);
406
407
return ret;
408
}
409
410
static int hte_bind_ts_info_locked(struct hte_ts_info *ei,
411
struct hte_ts_desc *desc, u32 x_id)
412
{
413
int ret = 0;
414
415
mutex_lock(&ei->req_mlock);
416
417
if (test_bit(HTE_TS_REQ, &ei->flags)) {
418
dev_dbg(ei->gdev->chip->dev, "id:%u is already requested\n",
419
desc->attr.line_id);
420
ret = -EUSERS;
421
goto out;
422
}
423
424
set_bit(HTE_TS_REQ, &ei->flags);
425
desc->hte_data = ei;
426
ei->xlated_id = x_id;
427
428
out:
429
mutex_unlock(&ei->req_mlock);
430
431
return ret;
432
}
433
434
static struct hte_device *of_node_to_htedevice(struct device_node *np)
435
{
436
struct hte_device *gdev;
437
438
spin_lock(&hte_lock);
439
440
list_for_each_entry(gdev, &hte_devices, list)
441
if (gdev->chip && gdev->chip->dev &&
442
device_match_of_node(gdev->chip->dev, np)) {
443
spin_unlock(&hte_lock);
444
return gdev;
445
}
446
447
spin_unlock(&hte_lock);
448
449
return ERR_PTR(-ENODEV);
450
}
451
452
static struct hte_device *hte_find_dev_from_linedata(struct hte_ts_desc *desc)
453
{
454
struct hte_device *gdev;
455
456
spin_lock(&hte_lock);
457
458
list_for_each_entry(gdev, &hte_devices, list)
459
if (gdev->chip && gdev->chip->match_from_linedata) {
460
if (!gdev->chip->match_from_linedata(gdev->chip, desc))
461
continue;
462
spin_unlock(&hte_lock);
463
return gdev;
464
}
465
466
spin_unlock(&hte_lock);
467
468
return ERR_PTR(-ENODEV);
469
}
470
471
/**
472
* of_hte_req_count - Return the number of entities to timestamp.
473
*
474
* The function returns the total count of the requested entities to timestamp
475
* by parsing device tree.
476
*
477
* @dev: The HTE consumer.
478
*
479
* Returns: Positive number on success, -ENOENT if no entries,
480
* -EINVAL for other errors.
481
*/
482
int of_hte_req_count(struct device *dev)
483
{
484
int count;
485
486
if (!dev || !dev->of_node)
487
return -EINVAL;
488
489
count = of_count_phandle_with_args(dev->of_node, "timestamps",
490
"#timestamp-cells");
491
492
return count ? count : -ENOENT;
493
}
494
EXPORT_SYMBOL_GPL(of_hte_req_count);
495
496
static inline struct hte_device *hte_get_dev(struct hte_ts_desc *desc)
497
{
498
return hte_find_dev_from_linedata(desc);
499
}
500
501
static struct hte_device *hte_of_get_dev(struct device *dev,
502
struct hte_ts_desc *desc,
503
int index,
504
struct of_phandle_args *args,
505
bool *free_name)
506
{
507
int ret;
508
struct device_node *np;
509
char *temp;
510
511
if (!dev->of_node)
512
return ERR_PTR(-EINVAL);
513
514
np = dev->of_node;
515
516
if (!of_property_present(np, "timestamp-names")) {
517
/* Let hte core construct it during request time */
518
desc->attr.name = NULL;
519
} else {
520
ret = of_property_read_string_index(np, "timestamp-names",
521
index, &desc->attr.name);
522
if (ret) {
523
pr_err("can't parse \"timestamp-names\" property\n");
524
return ERR_PTR(ret);
525
}
526
*free_name = false;
527
if (desc->attr.name) {
528
temp = skip_spaces(desc->attr.name);
529
if (!*temp)
530
desc->attr.name = NULL;
531
}
532
}
533
534
ret = of_parse_phandle_with_args(np, "timestamps", "#timestamp-cells",
535
index, args);
536
if (ret) {
537
pr_err("%s(): can't parse \"timestamps\" property\n",
538
__func__);
539
return ERR_PTR(ret);
540
}
541
542
of_node_put(args->np);
543
544
return of_node_to_htedevice(args->np);
545
}
546
547
/**
548
* hte_ts_get() - The function to initialize and obtain HTE desc.
549
*
550
* The function initializes the consumer provided HTE descriptor. If consumer
551
* has device tree node, index is used to parse the line id and other details.
552
* The function needs to be called before using any request APIs.
553
*
554
* @dev: HTE consumer/client device, used in case of parsing device tree node.
555
* @desc: Pre-allocated timestamp descriptor.
556
* @index: The index will be used as an index to parse line_id from the
557
* device tree node if node is present.
558
*
559
* Context: Holds mutex lock.
560
* Returns: Returns 0 on success or negative error code on failure.
561
*/
562
int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index)
563
{
564
struct hte_device *gdev;
565
struct hte_ts_info *ei;
566
const struct fwnode_handle *fwnode;
567
struct of_phandle_args args;
568
u32 xlated_id;
569
int ret;
570
bool free_name = false;
571
572
if (!desc)
573
return -EINVAL;
574
575
fwnode = dev ? dev_fwnode(dev) : NULL;
576
577
if (is_of_node(fwnode))
578
gdev = hte_of_get_dev(dev, desc, index, &args, &free_name);
579
else
580
gdev = hte_get_dev(desc);
581
582
if (IS_ERR(gdev)) {
583
pr_err("%s() no hte dev found\n", __func__);
584
return PTR_ERR(gdev);
585
}
586
587
if (!try_module_get(gdev->owner))
588
return -ENODEV;
589
590
if (!gdev->chip) {
591
pr_err("%s(): requested id does not have provider\n",
592
__func__);
593
ret = -ENODEV;
594
goto put;
595
}
596
597
if (is_of_node(fwnode)) {
598
if (!gdev->chip->xlate_of)
599
ret = -EINVAL;
600
else
601
ret = gdev->chip->xlate_of(gdev->chip, &args,
602
desc, &xlated_id);
603
} else {
604
if (!gdev->chip->xlate_plat)
605
ret = -EINVAL;
606
else
607
ret = gdev->chip->xlate_plat(gdev->chip, desc,
608
&xlated_id);
609
}
610
611
if (ret < 0)
612
goto put;
613
614
ei = &gdev->ei[xlated_id];
615
616
ret = hte_bind_ts_info_locked(ei, desc, xlated_id);
617
if (ret)
618
goto put;
619
620
ei->free_attr_name = free_name;
621
622
return 0;
623
624
put:
625
module_put(gdev->owner);
626
return ret;
627
}
628
EXPORT_SYMBOL_GPL(hte_ts_get);
629
630
static void __devm_hte_release_ts(void *res)
631
{
632
hte_ts_put(res);
633
}
634
635
/**
636
* hte_request_ts_ns() - The API to request and enable hardware timestamp in
637
* nanoseconds.
638
*
639
* The entity is provider specific for example, GPIO lines, signals, buses
640
* etc...The API allocates necessary resources and enables the timestamp.
641
*
642
* @desc: Pre-allocated and initialized timestamp descriptor.
643
* @cb: Callback to push the timestamp data to consumer.
644
* @tcb: Optional callback. If its provided, subsystem initializes
645
* workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
646
* @data: Client data, used during cb and tcb callbacks.
647
*
648
* Context: Holds mutex lock.
649
* Returns: Returns 0 on success or negative error code on failure.
650
*/
651
int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb,
652
hte_ts_sec_cb_t tcb, void *data)
653
{
654
int ret;
655
struct hte_ts_info *ei;
656
657
if (!desc || !desc->hte_data || !cb)
658
return -EINVAL;
659
660
ei = desc->hte_data;
661
if (!ei || !ei->gdev)
662
return -EINVAL;
663
664
ret = __hte_req_ts(desc, cb, tcb, data);
665
if (ret < 0) {
666
dev_err(ei->gdev->chip->dev,
667
"failed to request id: %d\n", desc->attr.line_id);
668
return ret;
669
}
670
671
return 0;
672
}
673
EXPORT_SYMBOL_GPL(hte_request_ts_ns);
674
675
/**
676
* devm_hte_request_ts_ns() - Resource managed API to request and enable
677
* hardware timestamp in nanoseconds.
678
*
679
* The entity is provider specific for example, GPIO lines, signals, buses
680
* etc...The API allocates necessary resources and enables the timestamp. It
681
* deallocates and disables automatically when the consumer exits.
682
*
683
* @dev: HTE consumer/client device.
684
* @desc: Pre-allocated and initialized timestamp descriptor.
685
* @cb: Callback to push the timestamp data to consumer.
686
* @tcb: Optional callback. If its provided, subsystem initializes
687
* workqueue. It is called when cb returns HTE_RUN_SECOND_CB.
688
* @data: Client data, used during cb and tcb callbacks.
689
*
690
* Context: Holds mutex lock.
691
* Returns: Returns 0 on success or negative error code on failure.
692
*/
693
int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc,
694
hte_ts_cb_t cb, hte_ts_sec_cb_t tcb,
695
void *data)
696
{
697
int err;
698
699
if (!dev)
700
return -EINVAL;
701
702
err = hte_request_ts_ns(desc, cb, tcb, data);
703
if (err)
704
return err;
705
706
err = devm_add_action_or_reset(dev, __devm_hte_release_ts, desc);
707
if (err)
708
return err;
709
710
return 0;
711
}
712
EXPORT_SYMBOL_GPL(devm_hte_request_ts_ns);
713
714
/**
715
* hte_init_line_attr() - Initialize line attributes.
716
*
717
* Zeroes out line attributes and initializes with provided arguments.
718
* The function needs to be called before calling any consumer facing
719
* functions.
720
*
721
* @desc: Pre-allocated timestamp descriptor.
722
* @line_id: line id.
723
* @edge_flags: edge flags related to line_id.
724
* @name: name of the line.
725
* @data: line data related to line_id.
726
*
727
* Context: Any.
728
* Returns: 0 on success or negative error code for the failure.
729
*/
730
int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id,
731
unsigned long edge_flags, const char *name, void *data)
732
{
733
if (!desc)
734
return -EINVAL;
735
736
memset(&desc->attr, 0, sizeof(desc->attr));
737
738
desc->attr.edge_flags = edge_flags;
739
desc->attr.line_id = line_id;
740
desc->attr.line_data = data;
741
if (name) {
742
name = kstrdup_const(name, GFP_KERNEL);
743
if (!name)
744
return -ENOMEM;
745
}
746
747
desc->attr.name = name;
748
749
return 0;
750
}
751
EXPORT_SYMBOL_GPL(hte_init_line_attr);
752
753
/**
754
* hte_get_clk_src_info() - Get the clock source information for a ts
755
* descriptor.
756
*
757
* @desc: ts descriptor, same as returned from request API.
758
* @ci: The API fills this structure with the clock information data.
759
*
760
* Context: Any context.
761
* Returns: 0 on success else negative error code on failure.
762
*/
763
int hte_get_clk_src_info(const struct hte_ts_desc *desc,
764
struct hte_clk_info *ci)
765
{
766
struct hte_chip *chip;
767
struct hte_ts_info *ei;
768
769
if (!desc || !desc->hte_data || !ci) {
770
pr_debug("%s:%d\n", __func__, __LINE__);
771
return -EINVAL;
772
}
773
774
ei = desc->hte_data;
775
if (!ei->gdev || !ei->gdev->chip)
776
return -EINVAL;
777
778
chip = ei->gdev->chip;
779
if (!chip->ops->get_clk_src_info)
780
return -EOPNOTSUPP;
781
782
return chip->ops->get_clk_src_info(chip, ci);
783
}
784
EXPORT_SYMBOL_GPL(hte_get_clk_src_info);
785
786
/**
787
* hte_push_ts_ns() - Push timestamp data in nanoseconds.
788
*
789
* It is used by the provider to push timestamp data.
790
*
791
* @chip: The HTE chip, used during the registration.
792
* @xlated_id: entity id understood by both subsystem and provider, this is
793
* obtained from xlate callback during request API.
794
* @data: timestamp data.
795
*
796
* Returns: 0 on success or a negative error code on failure.
797
*/
798
int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id,
799
struct hte_ts_data *data)
800
{
801
enum hte_return ret;
802
int st = 0;
803
struct hte_ts_info *ei;
804
unsigned long flag;
805
806
if (!chip || !data || !chip->gdev)
807
return -EINVAL;
808
809
if (xlated_id >= chip->nlines)
810
return -EINVAL;
811
812
ei = &chip->gdev->ei[xlated_id];
813
814
spin_lock_irqsave(&ei->slock, flag);
815
816
/* timestamp sequence counter */
817
data->seq = ei->seq++;
818
819
if (!test_bit(HTE_TS_REGISTERED, &ei->flags) ||
820
test_bit(HTE_TS_DISABLE, &ei->flags)) {
821
dev_dbg(chip->dev, "Unknown timestamp push\n");
822
atomic_inc(&ei->dropped_ts);
823
st = -EINVAL;
824
goto unlock;
825
}
826
827
ret = ei->cb(data, ei->cl_data);
828
if (ret == HTE_RUN_SECOND_CB && ei->tcb) {
829
queue_work(system_unbound_wq, &ei->cb_work);
830
set_bit(HTE_TS_QUEUE_WK, &ei->flags);
831
}
832
833
unlock:
834
spin_unlock_irqrestore(&ei->slock, flag);
835
836
return st;
837
}
838
EXPORT_SYMBOL_GPL(hte_push_ts_ns);
839
840
static int hte_register_chip(struct hte_chip *chip)
841
{
842
struct hte_device *gdev;
843
u32 i;
844
845
if (!chip || !chip->dev || !chip->dev->of_node)
846
return -EINVAL;
847
848
if (!chip->ops || !chip->ops->request || !chip->ops->release) {
849
dev_err(chip->dev, "Driver needs to provide ops\n");
850
return -EINVAL;
851
}
852
853
gdev = kzalloc(struct_size(gdev, ei, chip->nlines), GFP_KERNEL);
854
if (!gdev)
855
return -ENOMEM;
856
857
gdev->chip = chip;
858
chip->gdev = gdev;
859
gdev->nlines = chip->nlines;
860
gdev->sdev = chip->dev;
861
862
for (i = 0; i < chip->nlines; i++) {
863
gdev->ei[i].gdev = gdev;
864
mutex_init(&gdev->ei[i].req_mlock);
865
spin_lock_init(&gdev->ei[i].slock);
866
}
867
868
if (chip->dev->driver)
869
gdev->owner = chip->dev->driver->owner;
870
else
871
gdev->owner = THIS_MODULE;
872
873
of_node_get(chip->dev->of_node);
874
875
INIT_LIST_HEAD(&gdev->list);
876
877
spin_lock(&hte_lock);
878
list_add_tail(&gdev->list, &hte_devices);
879
spin_unlock(&hte_lock);
880
881
hte_chip_dbgfs_init(gdev);
882
883
dev_dbg(chip->dev, "Added hte chip\n");
884
885
return 0;
886
}
887
888
static int hte_unregister_chip(struct hte_chip *chip)
889
{
890
struct hte_device *gdev;
891
892
if (!chip)
893
return -EINVAL;
894
895
gdev = chip->gdev;
896
897
spin_lock(&hte_lock);
898
list_del(&gdev->list);
899
spin_unlock(&hte_lock);
900
901
gdev->chip = NULL;
902
903
of_node_put(chip->dev->of_node);
904
debugfs_remove_recursive(gdev->dbg_root);
905
kfree(gdev);
906
907
dev_dbg(chip->dev, "Removed hte chip\n");
908
909
return 0;
910
}
911
912
static void _hte_devm_unregister_chip(void *chip)
913
{
914
hte_unregister_chip(chip);
915
}
916
917
/**
918
* devm_hte_register_chip() - Resource managed API to register HTE chip.
919
*
920
* It is used by the provider to register itself with the HTE subsystem.
921
* The unregistration is done automatically when the provider exits.
922
*
923
* @chip: the HTE chip to add to subsystem.
924
*
925
* Returns: 0 on success or a negative error code on failure.
926
*/
927
int devm_hte_register_chip(struct hte_chip *chip)
928
{
929
int err;
930
931
err = hte_register_chip(chip);
932
if (err)
933
return err;
934
935
err = devm_add_action_or_reset(chip->dev, _hte_devm_unregister_chip,
936
chip);
937
if (err)
938
return err;
939
940
return 0;
941
}
942
EXPORT_SYMBOL_GPL(devm_hte_register_chip);
943
944