@@ -20,9 +20,15 @@ struct platform_profile_handler {
2020 struct device class_dev ;
2121 int minor ;
2222 unsigned long choices [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
23+ unsigned long hidden_choices [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
2324 const struct platform_profile_ops * ops ;
2425};
2526
27+ struct aggregate_choices_data {
28+ unsigned long aggregate [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
29+ int count ;
30+ };
31+
2632static const char * const profile_names [] = {
2733 [PLATFORM_PROFILE_LOW_POWER ] = "low-power" ,
2834 [PLATFORM_PROFILE_COOL ] = "cool" ,
@@ -72,7 +78,7 @@ static int _store_class_profile(struct device *dev, void *data)
7278
7379 lockdep_assert_held (& profile_lock );
7480 handler = to_pprof_handler (dev );
75- if (!test_bit (* bit , handler -> choices ))
81+ if (!test_bit (* bit , handler -> choices ) && ! test_bit ( * bit , handler -> hidden_choices ) )
7682 return - EOPNOTSUPP ;
7783
7884 return handler -> ops -> profile_set (dev , * bit );
@@ -238,21 +244,44 @@ static const struct class platform_profile_class = {
238244/**
239245 * _aggregate_choices - Aggregate the available profile choices
240246 * @dev: The device
241- * @data: The available profile choices
247+ * @arg: struct aggregate_choices_data
242248 *
243249 * Return: 0 on success, -errno on failure
244250 */
245- static int _aggregate_choices (struct device * dev , void * data )
251+ static int _aggregate_choices (struct device * dev , void * arg )
246252{
253+ unsigned long tmp [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
254+ struct aggregate_choices_data * data = arg ;
247255 struct platform_profile_handler * handler ;
248- unsigned long * aggregate = data ;
249256
250257 lockdep_assert_held (& profile_lock );
251258 handler = to_pprof_handler (dev );
252- if (test_bit (PLATFORM_PROFILE_LAST , aggregate ))
253- bitmap_copy (aggregate , handler -> choices , PLATFORM_PROFILE_LAST );
259+ bitmap_or (tmp , handler -> choices , handler -> hidden_choices , PLATFORM_PROFILE_LAST );
260+ if (test_bit (PLATFORM_PROFILE_LAST , data -> aggregate ))
261+ bitmap_copy (data -> aggregate , tmp , PLATFORM_PROFILE_LAST );
254262 else
255- bitmap_and (aggregate , handler -> choices , aggregate , PLATFORM_PROFILE_LAST );
263+ bitmap_and (data -> aggregate , tmp , data -> aggregate , PLATFORM_PROFILE_LAST );
264+ data -> count ++ ;
265+
266+ return 0 ;
267+ }
268+
269+ /**
270+ * _remove_hidden_choices - Remove hidden choices from aggregate data
271+ * @dev: The device
272+ * @arg: struct aggregate_choices_data
273+ *
274+ * Return: 0 on success, -errno on failure
275+ */
276+ static int _remove_hidden_choices (struct device * dev , void * arg )
277+ {
278+ struct aggregate_choices_data * data = arg ;
279+ struct platform_profile_handler * handler ;
280+
281+ lockdep_assert_held (& profile_lock );
282+ handler = to_pprof_handler (dev );
283+ bitmap_andnot (data -> aggregate , handler -> choices ,
284+ handler -> hidden_choices , PLATFORM_PROFILE_LAST );
256285
257286 return 0 ;
258287}
@@ -269,22 +298,31 @@ static ssize_t platform_profile_choices_show(struct device *dev,
269298 struct device_attribute * attr ,
270299 char * buf )
271300{
272- unsigned long aggregate [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
301+ struct aggregate_choices_data data = {
302+ .aggregate = { [0 ... BITS_TO_LONGS (PLATFORM_PROFILE_LAST ) - 1 ] = ~0UL },
303+ .count = 0 ,
304+ };
273305 int err ;
274306
275- set_bit (PLATFORM_PROFILE_LAST , aggregate );
307+ set_bit (PLATFORM_PROFILE_LAST , data . aggregate );
276308 scoped_cond_guard (mutex_intr , return - ERESTARTSYS , & profile_lock ) {
277309 err = class_for_each_device (& platform_profile_class , NULL ,
278- aggregate , _aggregate_choices );
310+ & data , _aggregate_choices );
279311 if (err )
280312 return err ;
313+ if (data .count == 1 ) {
314+ err = class_for_each_device (& platform_profile_class , NULL ,
315+ & data , _remove_hidden_choices );
316+ if (err )
317+ return err ;
318+ }
281319 }
282320
283321 /* no profile handler registered any more */
284- if (bitmap_empty (aggregate , PLATFORM_PROFILE_LAST ))
322+ if (bitmap_empty (data . aggregate , PLATFORM_PROFILE_LAST ))
285323 return - EINVAL ;
286324
287- return _commmon_choices_show (aggregate , buf );
325+ return _commmon_choices_show (data . aggregate , buf );
288326}
289327
290328/**
@@ -372,21 +410,24 @@ static ssize_t platform_profile_store(struct device *dev,
372410 struct device_attribute * attr ,
373411 const char * buf , size_t count )
374412{
375- unsigned long choices [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
413+ struct aggregate_choices_data data = {
414+ .aggregate = { [0 ... BITS_TO_LONGS (PLATFORM_PROFILE_LAST ) - 1 ] = ~0UL },
415+ .count = 0 ,
416+ };
376417 int ret ;
377418 int i ;
378419
379420 /* Scan for a matching profile */
380421 i = sysfs_match_string (profile_names , buf );
381422 if (i < 0 || i == PLATFORM_PROFILE_CUSTOM )
382423 return - EINVAL ;
383- set_bit (PLATFORM_PROFILE_LAST , choices );
424+ set_bit (PLATFORM_PROFILE_LAST , data . aggregate );
384425 scoped_cond_guard (mutex_intr , return - ERESTARTSYS , & profile_lock ) {
385426 ret = class_for_each_device (& platform_profile_class , NULL ,
386- choices , _aggregate_choices );
427+ & data , _aggregate_choices );
387428 if (ret )
388429 return ret ;
389- if (!test_bit (i , choices ))
430+ if (!test_bit (i , data . aggregate ))
390431 return - EOPNOTSUPP ;
391432
392433 ret = class_for_each_device (& platform_profile_class , NULL , & i ,
@@ -437,12 +478,15 @@ EXPORT_SYMBOL_GPL(platform_profile_notify);
437478
438479int platform_profile_cycle (void )
439480{
481+ struct aggregate_choices_data data = {
482+ .aggregate = { [0 ... BITS_TO_LONGS (PLATFORM_PROFILE_LAST ) - 1 ] = ~0UL },
483+ .count = 0 ,
484+ };
440485 enum platform_profile_option next = PLATFORM_PROFILE_LAST ;
441486 enum platform_profile_option profile = PLATFORM_PROFILE_LAST ;
442- unsigned long choices [BITS_TO_LONGS (PLATFORM_PROFILE_LAST )];
443487 int err ;
444488
445- set_bit (PLATFORM_PROFILE_LAST , choices );
489+ set_bit (PLATFORM_PROFILE_LAST , data . aggregate );
446490 scoped_cond_guard (mutex_intr , return - ERESTARTSYS , & profile_lock ) {
447491 err = class_for_each_device (& platform_profile_class , NULL ,
448492 & profile , _aggregate_profiles );
@@ -454,14 +498,14 @@ int platform_profile_cycle(void)
454498 return - EINVAL ;
455499
456500 err = class_for_each_device (& platform_profile_class , NULL ,
457- choices , _aggregate_choices );
501+ & data , _aggregate_choices );
458502 if (err )
459503 return err ;
460504
461505 /* never iterate into a custom if all drivers supported it */
462- clear_bit (PLATFORM_PROFILE_CUSTOM , choices );
506+ clear_bit (PLATFORM_PROFILE_CUSTOM , data . aggregate );
463507
464- next = find_next_bit_wrap (choices ,
508+ next = find_next_bit_wrap (data . aggregate ,
465509 PLATFORM_PROFILE_LAST ,
466510 profile + 1 );
467511
@@ -507,6 +551,14 @@ struct device *platform_profile_register(struct device *dev, const char *name,
507551 return ERR_PTR (- EINVAL );
508552 }
509553
554+ if (ops -> hidden_choices ) {
555+ err = ops -> hidden_choices (drvdata , pprof -> hidden_choices );
556+ if (err ) {
557+ dev_err (dev , "platform_profile hidden_choices failed\n" );
558+ return ERR_PTR (err );
559+ }
560+ }
561+
510562 guard (mutex )(& profile_lock );
511563
512564 /* create class interface for individual handler */
0 commit comments