@@ -373,7 +373,7 @@ static int iter_perf_levels_update_state(struct scmi_iterator_state *st,
373373 return 0 ;
374374}
375375
376- static inline void
376+ static inline int
377377process_response_opp (struct device * dev , struct perf_dom_info * dom ,
378378 struct scmi_opp * opp , unsigned int loop_idx ,
379379 const struct scmi_msg_resp_perf_describe_levels * r )
@@ -386,12 +386,16 @@ process_response_opp(struct device *dev, struct perf_dom_info *dom,
386386 le16_to_cpu (r -> opp [loop_idx ].transition_latency_us );
387387
388388 ret = xa_insert (& dom -> opps_by_lvl , opp -> perf , opp , GFP_KERNEL );
389- if (ret )
389+ if (ret ) {
390390 dev_warn (dev , "Failed to add opps_by_lvl at %d for %s - ret:%d\n" ,
391391 opp -> perf , dom -> info .name , ret );
392+ return ret ;
393+ }
394+
395+ return 0 ;
392396}
393397
394- static inline void
398+ static inline int
395399process_response_opp_v4 (struct device * dev , struct perf_dom_info * dom ,
396400 struct scmi_opp * opp , unsigned int loop_idx ,
397401 const struct scmi_msg_resp_perf_describe_levels_v4 * r )
@@ -404,9 +408,11 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
404408 le16_to_cpu (r -> opp [loop_idx ].transition_latency_us );
405409
406410 ret = xa_insert (& dom -> opps_by_lvl , opp -> perf , opp , GFP_KERNEL );
407- if (ret )
411+ if (ret ) {
408412 dev_warn (dev , "Failed to add opps_by_lvl at %d for %s - ret:%d\n" ,
409413 opp -> perf , dom -> info .name , ret );
414+ return ret ;
415+ }
410416
411417 /* Note that PERF v4 reports always five 32-bit words */
412418 opp -> indicative_freq = le32_to_cpu (r -> opp [loop_idx ].indicative_freq );
@@ -415,30 +421,44 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
415421
416422 ret = xa_insert (& dom -> opps_by_idx , opp -> level_index , opp ,
417423 GFP_KERNEL );
418- if (ret )
424+ if (ret ) {
419425 dev_warn (dev ,
420426 "Failed to add opps_by_idx at %d for %s - ret:%d\n" ,
421427 opp -> level_index , dom -> info .name , ret );
422428
429+ /* Cleanup by_lvl too */
430+ xa_erase (& dom -> opps_by_lvl , opp -> perf );
431+
432+ return ret ;
433+ }
434+
423435 hash_add (dom -> opps_by_freq , & opp -> hash , opp -> indicative_freq );
424436 }
437+
438+ return 0 ;
425439}
426440
427441static int
428442iter_perf_levels_process_response (const struct scmi_protocol_handle * ph ,
429443 const void * response ,
430444 struct scmi_iterator_state * st , void * priv )
431445{
446+ int ret ;
432447 struct scmi_opp * opp ;
433448 struct scmi_perf_ipriv * p = priv ;
434449
435- opp = & p -> perf_dom -> opp [st -> desc_index + st -> loop_idx ];
450+ opp = & p -> perf_dom -> opp [p -> perf_dom -> opp_count ];
436451 if (PROTOCOL_REV_MAJOR (p -> version ) <= 0x3 )
437- process_response_opp (ph -> dev , p -> perf_dom , opp , st -> loop_idx ,
438- response );
452+ ret = process_response_opp (ph -> dev , p -> perf_dom , opp ,
453+ st -> loop_idx , response );
439454 else
440- process_response_opp_v4 (ph -> dev , p -> perf_dom , opp , st -> loop_idx ,
441- response );
455+ ret = process_response_opp_v4 (ph -> dev , p -> perf_dom , opp ,
456+ st -> loop_idx , response );
457+
458+ /* Skip BAD duplicates received from firmware */
459+ if (ret )
460+ return ret == - EBUSY ? 0 : ret ;
461+
442462 p -> perf_dom -> opp_count ++ ;
443463
444464 dev_dbg (ph -> dev , "Level %d Power %d Latency %dus Ifreq %d Index %d\n" ,
0 commit comments