1
1
// SPDX-License-Identifier: GPL-2.0
2
- /* Marvell CN10K DRAM Subsystem (DSS) Performance Monitor Driver
2
+ /*
3
+ * Marvell CN10K DRAM Subsystem (DSS) Performance Monitor Driver
3
4
*
4
- * Copyright (C) 2021 Marvell.
5
+ * Copyright (C) 2021-2024 Marvell.
5
6
*/
6
7
7
8
#include <linux/init.h>
14
15
#include <linux/platform_device.h>
15
16
16
17
/* Performance Counters Operating Mode Control Registers */
17
- #define DDRC_PERF_CNT_OP_MODE_CTRL 0x8020
18
- #define OP_MODE_CTRL_VAL_MANNUAL 0x1
18
+ #define CN10K_DDRC_PERF_CNT_OP_MODE_CTRL 0x8020
19
+ #define OP_MODE_CTRL_VAL_MANUAL 0x1
19
20
20
21
/* Performance Counters Start Operation Control Registers */
21
- #define DDRC_PERF_CNT_START_OP_CTRL 0x8028
22
+ #define CN10K_DDRC_PERF_CNT_START_OP_CTRL 0x8028
22
23
#define START_OP_CTRL_VAL_START 0x1ULL
23
24
#define START_OP_CTRL_VAL_ACTIVE 0x2
24
25
25
26
/* Performance Counters End Operation Control Registers */
26
- #define DDRC_PERF_CNT_END_OP_CTRL 0x8030
27
+ #define CN10K_DDRC_PERF_CNT_END_OP_CTRL 0x8030
27
28
#define END_OP_CTRL_VAL_END 0x1ULL
28
29
29
30
/* Performance Counters End Status Registers */
30
- #define DDRC_PERF_CNT_END_STATUS 0x8038
31
+ #define CN10K_DDRC_PERF_CNT_END_STATUS 0x8038
31
32
#define END_STATUS_VAL_END_TIMER_MODE_END 0x1
32
33
33
34
/* Performance Counters Configuration Registers */
34
- #define DDRC_PERF_CFG_BASE 0x8040
35
+ #define CN10K_DDRC_PERF_CFG_BASE 0x8040
35
36
36
37
/* 8 Generic event counter + 2 fixed event counters */
37
38
#define DDRC_PERF_NUM_GEN_COUNTERS 8
42
43
DDRC_PERF_NUM_FIX_COUNTERS)
43
44
44
45
/* Generic event counter registers */
45
- #define DDRC_PERF_CFG (n ) (DDRC_PERF_CFG_BASE + 8 * (n))
46
+ #define DDRC_PERF_CFG (base , n ) ((base) + 8 * (n))
46
47
#define EVENT_ENABLE BIT_ULL(63)
47
48
48
49
/* Two dedicated event counters for DDR reads and writes */
49
50
#define EVENT_DDR_READS 101
50
51
#define EVENT_DDR_WRITES 100
51
52
53
+ #define DDRC_PERF_REG (base , n ) ((base) + 8 * (n))
52
54
/*
53
55
* programmable events IDs in programmable event counters.
54
56
* DO NOT change these event-id numbers, they are used to
102
104
#define EVENT_HIF_RD_OR_WR 1
103
105
104
106
/* Event counter value registers */
105
- #define DDRC_PERF_CNT_VALUE_BASE 0x8080
106
- #define DDRC_PERF_CNT_VALUE (n ) (DDRC_PERF_CNT_VALUE_BASE + 8 * (n))
107
+ #define CN10K_DDRC_PERF_CNT_VALUE_BASE 0x8080
107
108
108
109
/* Fixed event counter enable/disable register */
109
- #define DDRC_PERF_CNT_FREERUN_EN 0x80C0
110
+ #define CN10K_DDRC_PERF_CNT_FREERUN_EN 0x80C0
110
111
#define DDRC_PERF_FREERUN_WRITE_EN 0x1
111
112
#define DDRC_PERF_FREERUN_READ_EN 0x2
112
113
113
114
/* Fixed event counter control register */
114
- #define DDRC_PERF_CNT_FREERUN_CTRL 0x80C8
115
+ #define CN10K_DDRC_PERF_CNT_FREERUN_CTRL 0x80C8
115
116
#define DDRC_FREERUN_WRITE_CNT_CLR 0x1
116
117
#define DDRC_FREERUN_READ_CNT_CLR 0x2
117
118
118
- /* Fixed event counter value register */
119
- #define DDRC_PERF_CNT_VALUE_WR_OP 0x80D0
120
- #define DDRC_PERF_CNT_VALUE_RD_OP 0x80D8
121
119
#define DDRC_PERF_CNT_VALUE_OVERFLOW BIT_ULL(48)
122
120
#define DDRC_PERF_CNT_MAX_VALUE GENMASK_ULL(48, 0)
123
121
122
+ /* Fixed event counter value register */
123
+ #define CN10K_DDRC_PERF_CNT_VALUE_WR_OP 0x80D0
124
+ #define CN10K_DDRC_PERF_CNT_VALUE_RD_OP 0x80D8
125
+
124
126
struct cn10k_ddr_pmu {
125
127
struct pmu pmu ;
126
128
void __iomem * base ;
129
+ const struct ddr_pmu_platform_data * p_data ;
127
130
unsigned int cpu ;
128
131
struct device * dev ;
129
132
int active_events ;
@@ -134,6 +137,23 @@ struct cn10k_ddr_pmu {
134
137
135
138
#define to_cn10k_ddr_pmu (p ) container_of(p, struct cn10k_ddr_pmu, pmu)
136
139
140
+ struct ddr_pmu_platform_data {
141
+ u64 counter_overflow_val ;
142
+ u64 counter_max_val ;
143
+ u64 cnt_base ;
144
+ u64 cfg_base ;
145
+ u64 cnt_op_mode_ctrl ;
146
+ u64 cnt_start_op_ctrl ;
147
+ u64 cnt_end_op_ctrl ;
148
+ u64 cnt_end_status ;
149
+ u64 cnt_freerun_en ;
150
+ u64 cnt_freerun_ctrl ;
151
+ u64 cnt_freerun_clr ;
152
+ u64 cnt_value_wr_op ;
153
+ u64 cnt_value_rd_op ;
154
+ bool is_cn10k ;
155
+ };
156
+
137
157
static ssize_t cn10k_ddr_pmu_event_show (struct device * dev ,
138
158
struct device_attribute * attr ,
139
159
char * page )
@@ -354,6 +374,7 @@ static int cn10k_ddr_perf_event_init(struct perf_event *event)
354
374
static void cn10k_ddr_perf_counter_enable (struct cn10k_ddr_pmu * pmu ,
355
375
int counter , bool enable )
356
376
{
377
+ const struct ddr_pmu_platform_data * p_data = pmu -> p_data ;
357
378
u32 reg ;
358
379
u64 val ;
359
380
@@ -363,7 +384,7 @@ static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
363
384
}
364
385
365
386
if (counter < DDRC_PERF_NUM_GEN_COUNTERS ) {
366
- reg = DDRC_PERF_CFG (counter );
387
+ reg = DDRC_PERF_CFG (p_data -> cfg_base , counter );
367
388
val = readq_relaxed (pmu -> base + reg );
368
389
369
390
if (enable )
@@ -373,7 +394,8 @@ static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
373
394
374
395
writeq_relaxed (val , pmu -> base + reg );
375
396
} else {
376
- val = readq_relaxed (pmu -> base + DDRC_PERF_CNT_FREERUN_EN );
397
+ val = readq_relaxed (pmu -> base +
398
+ p_data -> cnt_freerun_en );
377
399
if (enable ) {
378
400
if (counter == DDRC_PERF_READ_COUNTER_IDX )
379
401
val |= DDRC_PERF_FREERUN_READ_EN ;
@@ -385,27 +407,33 @@ static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
385
407
else
386
408
val &= ~DDRC_PERF_FREERUN_WRITE_EN ;
387
409
}
388
- writeq_relaxed (val , pmu -> base + DDRC_PERF_CNT_FREERUN_EN );
410
+ writeq_relaxed (val , pmu -> base +
411
+ p_data -> cnt_freerun_en );
389
412
}
390
413
}
391
414
392
415
static u64 cn10k_ddr_perf_read_counter (struct cn10k_ddr_pmu * pmu , int counter )
393
416
{
417
+ const struct ddr_pmu_platform_data * p_data = pmu -> p_data ;
394
418
u64 val ;
395
419
396
420
if (counter == DDRC_PERF_READ_COUNTER_IDX )
397
- return readq_relaxed (pmu -> base + DDRC_PERF_CNT_VALUE_RD_OP );
421
+ return readq_relaxed (pmu -> base +
422
+ p_data -> cnt_value_rd_op );
398
423
399
424
if (counter == DDRC_PERF_WRITE_COUNTER_IDX )
400
- return readq_relaxed (pmu -> base + DDRC_PERF_CNT_VALUE_WR_OP );
425
+ return readq_relaxed (pmu -> base +
426
+ p_data -> cnt_value_wr_op );
401
427
402
- val = readq_relaxed (pmu -> base + DDRC_PERF_CNT_VALUE (counter ));
428
+ val = readq_relaxed (pmu -> base +
429
+ DDRC_PERF_REG (p_data -> cnt_base , counter ));
403
430
return val ;
404
431
}
405
432
406
433
static void cn10k_ddr_perf_event_update (struct perf_event * event )
407
434
{
408
435
struct cn10k_ddr_pmu * pmu = to_cn10k_ddr_pmu (event -> pmu );
436
+ const struct ddr_pmu_platform_data * p_data = pmu -> p_data ;
409
437
struct hw_perf_event * hwc = & event -> hw ;
410
438
u64 prev_count , new_count , mask ;
411
439
@@ -414,7 +442,7 @@ static void cn10k_ddr_perf_event_update(struct perf_event *event)
414
442
new_count = cn10k_ddr_perf_read_counter (pmu , hwc -> idx );
415
443
} while (local64_xchg (& hwc -> prev_count , new_count ) != prev_count );
416
444
417
- mask = DDRC_PERF_CNT_MAX_VALUE ;
445
+ mask = p_data -> counter_max_val ;
418
446
419
447
local64_add ((new_count - prev_count ) & mask , & event -> count );
420
448
}
@@ -435,6 +463,7 @@ static void cn10k_ddr_perf_event_start(struct perf_event *event, int flags)
435
463
static int cn10k_ddr_perf_event_add (struct perf_event * event , int flags )
436
464
{
437
465
struct cn10k_ddr_pmu * pmu = to_cn10k_ddr_pmu (event -> pmu );
466
+ const struct ddr_pmu_platform_data * p_data = pmu -> p_data ;
438
467
struct hw_perf_event * hwc = & event -> hw ;
439
468
u8 config = event -> attr .config ;
440
469
int counter , ret ;
@@ -454,7 +483,7 @@ static int cn10k_ddr_perf_event_add(struct perf_event *event, int flags)
454
483
455
484
if (counter < DDRC_PERF_NUM_GEN_COUNTERS ) {
456
485
/* Generic counters, configure event id */
457
- reg_offset = DDRC_PERF_CFG (counter );
486
+ reg_offset = DDRC_PERF_CFG (p_data -> cfg_base , counter );
458
487
ret = ddr_perf_get_event_bitmap (config , & val );
459
488
if (ret )
460
489
return ret ;
@@ -467,7 +496,7 @@ static int cn10k_ddr_perf_event_add(struct perf_event *event, int flags)
467
496
else
468
497
val = DDRC_FREERUN_WRITE_CNT_CLR ;
469
498
470
- writeq_relaxed (val , pmu -> base + DDRC_PERF_CNT_FREERUN_CTRL );
499
+ writeq_relaxed (val , pmu -> base + p_data -> cnt_freerun_ctrl );
471
500
}
472
501
473
502
hwc -> state |= PERF_HES_STOPPED ;
@@ -512,17 +541,19 @@ static void cn10k_ddr_perf_event_del(struct perf_event *event, int flags)
512
541
static void cn10k_ddr_perf_pmu_enable (struct pmu * pmu )
513
542
{
514
543
struct cn10k_ddr_pmu * ddr_pmu = to_cn10k_ddr_pmu (pmu );
544
+ const struct ddr_pmu_platform_data * p_data = ddr_pmu -> p_data ;
515
545
516
546
writeq_relaxed (START_OP_CTRL_VAL_START , ddr_pmu -> base +
517
- DDRC_PERF_CNT_START_OP_CTRL );
547
+ p_data -> cnt_start_op_ctrl );
518
548
}
519
549
520
550
static void cn10k_ddr_perf_pmu_disable (struct pmu * pmu )
521
551
{
522
552
struct cn10k_ddr_pmu * ddr_pmu = to_cn10k_ddr_pmu (pmu );
553
+ const struct ddr_pmu_platform_data * p_data = ddr_pmu -> p_data ;
523
554
524
555
writeq_relaxed (END_OP_CTRL_VAL_END , ddr_pmu -> base +
525
- DDRC_PERF_CNT_END_OP_CTRL );
556
+ p_data -> cnt_end_op_ctrl );
526
557
}
527
558
528
559
static void cn10k_ddr_perf_event_update_all (struct cn10k_ddr_pmu * pmu )
@@ -549,6 +580,7 @@ static void cn10k_ddr_perf_event_update_all(struct cn10k_ddr_pmu *pmu)
549
580
550
581
static irqreturn_t cn10k_ddr_pmu_overflow_handler (struct cn10k_ddr_pmu * pmu )
551
582
{
583
+ const struct ddr_pmu_platform_data * p_data = pmu -> p_data ;
552
584
struct perf_event * event ;
553
585
struct hw_perf_event * hwc ;
554
586
u64 prev_count , new_count ;
@@ -586,7 +618,7 @@ static irqreturn_t cn10k_ddr_pmu_overflow_handler(struct cn10k_ddr_pmu *pmu)
586
618
continue ;
587
619
588
620
value = cn10k_ddr_perf_read_counter (pmu , i );
589
- if (value == DDRC_PERF_CNT_MAX_VALUE ) {
621
+ if (value == p_data -> counter_max_val ) {
590
622
pr_info ("Counter-(%d) reached max value\n" , i );
591
623
cn10k_ddr_perf_event_update_all (pmu );
592
624
cn10k_ddr_perf_pmu_disable (& pmu -> pmu );
@@ -629,11 +661,32 @@ static int cn10k_ddr_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
629
661
return 0 ;
630
662
}
631
663
664
+ #if defined(CONFIG_ACPI ) || defined(CONFIG_OF )
665
+ static const struct ddr_pmu_platform_data cn10k_ddr_pmu_pdata = {
666
+ .counter_overflow_val = BIT_ULL (48 ),
667
+ .counter_max_val = GENMASK_ULL (48 , 0 ),
668
+ .cnt_base = CN10K_DDRC_PERF_CNT_VALUE_BASE ,
669
+ .cfg_base = CN10K_DDRC_PERF_CFG_BASE ,
670
+ .cnt_op_mode_ctrl = CN10K_DDRC_PERF_CNT_OP_MODE_CTRL ,
671
+ .cnt_start_op_ctrl = CN10K_DDRC_PERF_CNT_START_OP_CTRL ,
672
+ .cnt_end_op_ctrl = CN10K_DDRC_PERF_CNT_END_OP_CTRL ,
673
+ .cnt_end_status = CN10K_DDRC_PERF_CNT_END_STATUS ,
674
+ .cnt_freerun_en = CN10K_DDRC_PERF_CNT_FREERUN_EN ,
675
+ .cnt_freerun_ctrl = CN10K_DDRC_PERF_CNT_FREERUN_CTRL ,
676
+ .cnt_freerun_clr = 0 ,
677
+ .cnt_value_wr_op = CN10K_DDRC_PERF_CNT_VALUE_WR_OP ,
678
+ .cnt_value_rd_op = CN10K_DDRC_PERF_CNT_VALUE_RD_OP ,
679
+ .is_cn10k = TRUE,
680
+ };
681
+ #endif
682
+
632
683
static int cn10k_ddr_perf_probe (struct platform_device * pdev )
633
684
{
685
+ const struct ddr_pmu_platform_data * dev_data ;
634
686
struct cn10k_ddr_pmu * ddr_pmu ;
635
687
struct resource * res ;
636
688
void __iomem * base ;
689
+ bool is_cn10k ;
637
690
char * name ;
638
691
int ret ;
639
692
@@ -644,30 +697,41 @@ static int cn10k_ddr_perf_probe(struct platform_device *pdev)
644
697
ddr_pmu -> dev = & pdev -> dev ;
645
698
platform_set_drvdata (pdev , ddr_pmu );
646
699
700
+ dev_data = device_get_match_data (& pdev -> dev );
701
+ if (!dev_data ) {
702
+ dev_err (& pdev -> dev , "Error: No device match data found\n" );
703
+ return - ENODEV ;
704
+ }
705
+
647
706
base = devm_platform_get_and_ioremap_resource (pdev , 0 , & res );
648
707
if (IS_ERR (base ))
649
708
return PTR_ERR (base );
650
709
651
710
ddr_pmu -> base = base ;
652
711
653
- /* Setup the PMU counter to work in manual mode */
654
- writeq_relaxed (OP_MODE_CTRL_VAL_MANNUAL , ddr_pmu -> base +
655
- DDRC_PERF_CNT_OP_MODE_CTRL );
656
-
657
- ddr_pmu -> pmu = (struct pmu ) {
658
- .module = THIS_MODULE ,
659
- .capabilities = PERF_PMU_CAP_NO_EXCLUDE ,
660
- .task_ctx_nr = perf_invalid_context ,
661
- .attr_groups = cn10k_attr_groups ,
662
- .event_init = cn10k_ddr_perf_event_init ,
663
- .add = cn10k_ddr_perf_event_add ,
664
- .del = cn10k_ddr_perf_event_del ,
665
- .start = cn10k_ddr_perf_event_start ,
666
- .stop = cn10k_ddr_perf_event_stop ,
667
- .read = cn10k_ddr_perf_event_update ,
668
- .pmu_enable = cn10k_ddr_perf_pmu_enable ,
669
- .pmu_disable = cn10k_ddr_perf_pmu_disable ,
670
- };
712
+ ddr_pmu -> p_data = dev_data ;
713
+ is_cn10k = ddr_pmu -> p_data -> is_cn10k ;
714
+
715
+ if (is_cn10k ) {
716
+ /* Setup the PMU counter to work in manual mode */
717
+ writeq_relaxed (OP_MODE_CTRL_VAL_MANUAL , ddr_pmu -> base +
718
+ ddr_pmu -> p_data -> cnt_op_mode_ctrl );
719
+
720
+ ddr_pmu -> pmu = (struct pmu ) {
721
+ .module = THIS_MODULE ,
722
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE ,
723
+ .task_ctx_nr = perf_invalid_context ,
724
+ .attr_groups = cn10k_attr_groups ,
725
+ .event_init = cn10k_ddr_perf_event_init ,
726
+ .add = cn10k_ddr_perf_event_add ,
727
+ .del = cn10k_ddr_perf_event_del ,
728
+ .start = cn10k_ddr_perf_event_start ,
729
+ .stop = cn10k_ddr_perf_event_stop ,
730
+ .read = cn10k_ddr_perf_event_update ,
731
+ .pmu_enable = cn10k_ddr_perf_pmu_enable ,
732
+ .pmu_disable = cn10k_ddr_perf_pmu_disable ,
733
+ };
734
+ }
671
735
672
736
/* Choose this cpu to collect perf data */
673
737
ddr_pmu -> cpu = raw_smp_processor_id ();
@@ -688,7 +752,7 @@ static int cn10k_ddr_perf_probe(struct platform_device *pdev)
688
752
if (ret )
689
753
goto error ;
690
754
691
- pr_info ("CN10K DDR PMU Driver for ddrc@%llx\n" , res -> start );
755
+ pr_info ("DDR PMU Driver for ddrc@%llx\n" , res -> start );
692
756
return 0 ;
693
757
error :
694
758
cpuhp_state_remove_instance_nocalls (
@@ -710,15 +774,15 @@ static void cn10k_ddr_perf_remove(struct platform_device *pdev)
710
774
711
775
#ifdef CONFIG_OF
712
776
static const struct of_device_id cn10k_ddr_pmu_of_match [] = {
713
- { .compatible = "marvell,cn10k-ddr-pmu" , },
777
+ { .compatible = "marvell,cn10k-ddr-pmu" , . data = & cn10k_ddr_pmu_pdata },
714
778
{ },
715
779
};
716
780
MODULE_DEVICE_TABLE (of , cn10k_ddr_pmu_of_match );
717
781
#endif
718
782
719
783
#ifdef CONFIG_ACPI
720
784
static const struct acpi_device_id cn10k_ddr_pmu_acpi_match [] = {
721
- {"MRVL000A" , 0 },
785
+ {"MRVL000A" , ( kernel_ulong_t ) & cn10k_ddr_pmu_pdata },
722
786
{},
723
787
};
724
788
MODULE_DEVICE_TABLE (acpi , cn10k_ddr_pmu_acpi_match );
0 commit comments