1616 * The user should refer to the vendor technical documentation to get details
1717 * about the supported events.
1818 *
19- * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
19+ * Copyright (c) 2022-2023 , NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2020 *
2121 */
2222
2626#include <linux/interrupt.h>
2727#include <linux/io-64-nonatomic-lo-hi.h>
2828#include <linux/module.h>
29+ #include <linux/mutex.h>
2930#include <linux/perf_event.h>
3031#include <linux/platform_device.h>
3132
3233#include "arm_cspmu.h"
33- #include "nvidia_cspmu.h"
3434
3535#define PMUNAME "arm_cspmu"
3636#define DRVNAME "arm-cs-arch-pmu"
112112 */
113113#define HILOHI_MAX_POLL 1000
114114
115- /* JEDEC-assigned JEP106 identification code */
116- #define ARM_CSPMU_IMPL_ID_NVIDIA 0x36B
117-
118115static unsigned long arm_cspmu_cpuhp_state ;
119116
117+ static DEFINE_MUTEX (arm_cspmu_lock );
118+
120119static struct acpi_apmt_node * arm_cspmu_apmt_node (struct device * dev )
121120{
122121 return * (struct acpi_apmt_node * * )dev_get_platdata (dev );
@@ -373,27 +372,37 @@ static struct attribute_group arm_cspmu_cpumask_attr_group = {
373372 .attrs = arm_cspmu_cpumask_attrs ,
374373};
375374
376- struct impl_match {
377- u32 pmiidr ;
378- u32 mask ;
379- int (* impl_init_ops )(struct arm_cspmu * cspmu );
380- };
381-
382- static const struct impl_match impl_match [] = {
375+ static struct arm_cspmu_impl_match impl_match [] = {
383376 {
384- .pmiidr = ARM_CSPMU_IMPL_ID_NVIDIA ,
385- .mask = ARM_CSPMU_PMIIDR_IMPLEMENTER ,
386- .impl_init_ops = nv_cspmu_init_ops
377+ .module_name = "nvidia_cspmu" ,
378+ .pmiidr_val = ARM_CSPMU_IMPL_ID_NVIDIA ,
379+ .pmiidr_mask = ARM_CSPMU_PMIIDR_IMPLEMENTER ,
380+ .module = NULL ,
381+ .impl_init_ops = NULL ,
387382 },
388- {}
383+ {0 }
389384};
390385
386+ static struct arm_cspmu_impl_match * arm_cspmu_impl_match_get (u32 pmiidr )
387+ {
388+ struct arm_cspmu_impl_match * match = impl_match ;
389+
390+ for (; match -> pmiidr_val ; match ++ ) {
391+ u32 mask = match -> pmiidr_mask ;
392+
393+ if ((match -> pmiidr_val & mask ) == (pmiidr & mask ))
394+ return match ;
395+ }
396+
397+ return NULL ;
398+ }
399+
391400static int arm_cspmu_init_impl_ops (struct arm_cspmu * cspmu )
392401{
393- int ret ;
402+ int ret = 0 ;
394403 struct arm_cspmu_impl_ops * impl_ops = & cspmu -> impl .ops ;
395404 struct acpi_apmt_node * apmt_node = arm_cspmu_apmt_node (cspmu -> dev );
396- const struct impl_match * match = impl_match ;
405+ struct arm_cspmu_impl_match * match ;
397406
398407 /*
399408 * Get PMU implementer and product id from APMT node.
@@ -405,17 +414,36 @@ static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu)
405414 readl (cspmu -> base0 + PMIIDR );
406415
407416 /* Find implementer specific attribute ops. */
408- for (; match -> pmiidr ; match ++ ) {
409- const u32 mask = match -> mask ;
417+ match = arm_cspmu_impl_match_get (cspmu -> impl .pmiidr );
418+
419+ /* Load implementer module and initialize the callbacks. */
420+ if (match ) {
421+ mutex_lock (& arm_cspmu_lock );
422+
423+ if (match -> impl_init_ops ) {
424+ /* Prevent unload until PMU registration is done. */
425+ if (try_module_get (match -> module )) {
426+ cspmu -> impl .module = match -> module ;
427+ cspmu -> impl .match = match ;
428+ ret = match -> impl_init_ops (cspmu );
429+ if (ret )
430+ module_put (match -> module );
431+ } else {
432+ WARN (1 , "arm_cspmu failed to get module: %s\n" ,
433+ match -> module_name );
434+ ret = - EINVAL ;
435+ }
436+ } else {
437+ request_module_nowait (match -> module_name );
438+ ret = - EPROBE_DEFER ;
439+ }
410440
411- if ((match -> pmiidr & mask ) == (cspmu -> impl .pmiidr & mask )) {
412- ret = match -> impl_init_ops (cspmu );
413- if (ret )
414- return ret ;
441+ mutex_unlock (& arm_cspmu_lock );
415442
416- break ;
417- }
418- }
443+ if (ret )
444+ return ret ;
445+ } else
446+ cspmu -> impl .module = THIS_MODULE ;
419447
420448 /* Use default callbacks if implementer doesn't provide one. */
421449 CHECK_DEFAULT_IMPL_OPS (impl_ops , get_event_attrs );
@@ -478,11 +506,6 @@ arm_cspmu_alloc_attr_group(struct arm_cspmu *cspmu)
478506 struct attribute_group * * attr_groups = NULL ;
479507 struct device * dev = cspmu -> dev ;
480508 const struct arm_cspmu_impl_ops * impl_ops = & cspmu -> impl .ops ;
481- int ret ;
482-
483- ret = arm_cspmu_init_impl_ops (cspmu );
484- if (ret )
485- return NULL ;
486509
487510 cspmu -> identifier = impl_ops -> get_identifier (cspmu );
488511 cspmu -> name = impl_ops -> get_name (cspmu );
@@ -1149,7 +1172,7 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu)
11491172
11501173 cspmu -> pmu = (struct pmu ){
11511174 .task_ctx_nr = perf_invalid_context ,
1152- .module = THIS_MODULE ,
1175+ .module = cspmu -> impl . module ,
11531176 .pmu_enable = arm_cspmu_enable ,
11541177 .pmu_disable = arm_cspmu_disable ,
11551178 .event_init = arm_cspmu_event_init ,
@@ -1196,11 +1219,17 @@ static int arm_cspmu_device_probe(struct platform_device *pdev)
11961219 if (ret )
11971220 return ret ;
11981221
1199- ret = arm_cspmu_register_pmu (cspmu );
1222+ ret = arm_cspmu_init_impl_ops (cspmu );
12001223 if (ret )
12011224 return ret ;
12021225
1203- return 0 ;
1226+ ret = arm_cspmu_register_pmu (cspmu );
1227+
1228+ /* Matches arm_cspmu_init_impl_ops() above. */
1229+ if (cspmu -> impl .module != THIS_MODULE )
1230+ module_put (cspmu -> impl .module );
1231+
1232+ return ret ;
12041233}
12051234
12061235static int arm_cspmu_device_remove (struct platform_device * pdev )
@@ -1300,6 +1329,75 @@ static void __exit arm_cspmu_exit(void)
13001329 cpuhp_remove_multi_state (arm_cspmu_cpuhp_state );
13011330}
13021331
1332+ int arm_cspmu_impl_register (const struct arm_cspmu_impl_match * impl_match )
1333+ {
1334+ struct arm_cspmu_impl_match * match ;
1335+ int ret = 0 ;
1336+
1337+ match = arm_cspmu_impl_match_get (impl_match -> pmiidr_val );
1338+
1339+ if (match ) {
1340+ mutex_lock (& arm_cspmu_lock );
1341+
1342+ if (!match -> impl_init_ops ) {
1343+ match -> module = impl_match -> module ;
1344+ match -> impl_init_ops = impl_match -> impl_init_ops ;
1345+ } else {
1346+ /* Broken match table may contain non-unique entries */
1347+ WARN (1 , "arm_cspmu backend already registered for module: %s, pmiidr: 0x%x, mask: 0x%x\n" ,
1348+ match -> module_name ,
1349+ match -> pmiidr_val ,
1350+ match -> pmiidr_mask );
1351+
1352+ ret = - EINVAL ;
1353+ }
1354+
1355+ mutex_unlock (& arm_cspmu_lock );
1356+
1357+ if (!ret )
1358+ ret = driver_attach (& arm_cspmu_driver .driver );
1359+ } else {
1360+ pr_err ("arm_cspmu reg failed, unable to find a match for pmiidr: 0x%x\n" ,
1361+ impl_match -> pmiidr_val );
1362+
1363+ ret = - EINVAL ;
1364+ }
1365+
1366+ return ret ;
1367+ }
1368+ EXPORT_SYMBOL_GPL (arm_cspmu_impl_register );
1369+
1370+ static int arm_cspmu_match_device (struct device * dev , const void * match )
1371+ {
1372+ struct arm_cspmu * cspmu = platform_get_drvdata (to_platform_device (dev ));
1373+
1374+ return (cspmu && cspmu -> impl .match == match ) ? 1 : 0 ;
1375+ }
1376+
1377+ void arm_cspmu_impl_unregister (const struct arm_cspmu_impl_match * impl_match )
1378+ {
1379+ struct device * dev ;
1380+ struct arm_cspmu_impl_match * match ;
1381+
1382+ match = arm_cspmu_impl_match_get (impl_match -> pmiidr_val );
1383+
1384+ if (WARN_ON (!match ))
1385+ return ;
1386+
1387+ /* Unbind the driver from all matching backend devices. */
1388+ while ((dev = driver_find_device (& arm_cspmu_driver .driver , NULL ,
1389+ match , arm_cspmu_match_device )))
1390+ device_release_driver (dev );
1391+
1392+ mutex_lock (& arm_cspmu_lock );
1393+
1394+ match -> module = NULL ;
1395+ match -> impl_init_ops = NULL ;
1396+
1397+ mutex_unlock (& arm_cspmu_lock );
1398+ }
1399+ EXPORT_SYMBOL_GPL (arm_cspmu_impl_unregister );
1400+
13031401module_init (arm_cspmu_init );
13041402module_exit (arm_cspmu_exit );
13051403
0 commit comments