[Public]

> -----Original Message-----
> From: Jan Beulich <jbeul...@suse.com>
> Sent: Tuesday, March 25, 2025 5:58 PM
> To: Penny, Zheng <penny.zh...@amd.com>
> Cc: Huang, Ray <ray.hu...@amd.com>; Andrew Cooper
> <andrew.coop...@citrix.com>; Roger Pau Monné <roger....@citrix.com>; xen-
> de...@lists.xenproject.org; Jason Andryuk <jandr...@gmail.com>
> Subject: Re: [PATCH v3 09/15] xen/x86: introduce a new amd cppc driver for
> cpufreq scaling
>
> > +         * directly use nominal_mhz and lowest_mhz as the division
> > +         * will remove the frequency unit.
> > +         */
> > +        div = div ?: 1;
>
> Imo the cppc_data->lowest_mhz >= cppc_data->nominal_mhz case better
> wouldn't make it here, but use the fallback path below. Or special- case
> cppc_data->lowest_mhz == cppc_data->nominal_mhz: mul would
> (hopefully) be zero (i.e. there would be the expectation that
> data->caps.nominal_perf == data->caps.lowest_perf, yet no guarantee
> without checking), and hence ...

Okay, I'll drop the " div = div ?: 1", to strict the if() to
```
if ( cppc_data->cpc.lowest_mhz && cppc_data->cpc.nominal_mhz &&
     (cppc_data->cpc.lowest_mhz != cppc_data->cpc.nominal_mhz) )
```

>
> > +        offset = data->caps.nominal_perf -
> > +                 (mul * cppc_data->nominal_mhz) / div;
>
> ... offset = data->caps.nominal_perf regardless of "div" (as long as that's 
> not zero).
> I.e. the "equal" case may still be fine to take this path.
>
> Or is there a check somewhere that lowest_mhz <= nominal_mhz and lowest_perf
> <= nominal_perf, which I'm simply overlooking?
>

Yes. I overlooked the scenario that lowest_mhz > nominal_mhz and lowest_perf > 
nominal_perf
and I'll add the check on first read

> > +#define amd_get_freq(name)                                                 
> >  \
>
> The macro parameter is used just ...
>
> > +    static int amd_get_##name##_freq(const struct amd_cppc_drv_data
> > + *data,  \
>
> ... here, ...
>
> > +                                     unsigned int *freq)                   
> >  \
> > +    {                                                                      
> >  \
> > +        const struct xen_processor_cppc *cppc_data = data->cppc_data;      
> >  \
> > +        uint64_t mul, div, res;                                            
> >  \
> > +                                                                           
> >  \
> > +        if ( cppc_data->name##_mhz )                                       
> >  \
> > +        {                                                                  
> >  \
> > +            /* Switch to khz */                                            
> >  \
> > +            *freq = cppc_data->name##_mhz * 1000;                          
> >  \
>
> ... twice here forthe MHz value, and ...
>
> > +            return 0;                                                      
> >  \
> > +        }                                                                  
> >  \
> > +                                                                           
> >  \
> > +        /* Read Processor Max Speed(mhz) as anchor point */                
> >  \
> > +        mul = this_cpu(amd_max_freq_mhz);                                  
> >  \
> > +        if ( !mul )                                                        
> >  \
> > +            return -EINVAL;                                                
> >  \
> > +        div = data->caps.highest_perf;                                     
> >  \
> > +        res = (mul * data->caps.name##_perf * 1000) / div;                 
> >  \
>
> ... here for the respective perf indicator. Why does it take ...
>
> > +        if ( res > UINT_MAX )                                              
> >  \
> > +        {                                                                  
> >  \
> > +            printk(XENLOG_ERR                                              
> >  \
> > +                   "Frequeny exceeds maximum value UINT_MAX: %lu\n", res); 
> >  \
> > +            return -EINVAL;                                                
> >  \
> > +        }                                                                  
> >  \
> > +        *freq = (unsigned int)res;                                         
> >  \
> > +                                                                           
> >  \
> > +        return 0;                                                          
> >  \
> > +    }                                                                      
> >  \
> > +
> > +amd_get_freq(lowest);
> > +amd_get_freq(nominal);
>
> ... two almost identical functions, when one (with two extra input 
> parameters) would
> suffice?
>

I had a draft fix here, If it doesn't what you hope for, plz let me know
```
static int amd_get_lowest_and_nominal_freq(const struct amd_cppc_drv_data *data,
                                           unsigned int *lowest_freq,
                                           unsigned int *nominal_freq)
{
    const struct xen_processor_cppc *cppc_data = data->cppc_data;
    uint64_t mul, div, res;
    uint8_t perf;

    if ( !lowest_freq && !nominal_freq )
        return -EINVAL;

    if ( lowest_freq && cppc_data->cpc.lowest_mhz )
        /* Switch to khz */
        *lowest_freq = cppc_data->cpc.lowest_mhz * 1000;

    if ( nominal_freq && cppc_data->cpc.nominal_mhz )
        /* Switch to khz */
        *nominal_freq = cppc_data->cpc.nominal_mhz * 1000;

    /* Still have unresolved frequency */
    if ( (lowest_freq && !(*lowest_freq)) ||
         (nominal_freq && !(*nominal_freq)) )
    {
        do {
            /* Calculate lowest frequency firstly if need */
            if ( lowest_freq && !(*lowest_freq) )
                perf = data->caps.lowest_perf;
            else
                perf = data->caps.nominal_perf;

            /* Read Processor Max Speed(MHz) as anchor point */
            mul = this_cpu(amd_max_pxfreq_mhz);
            if ( mul == INVAL_FREQ_MHZ || !mul )
            {
                printk(XENLOG_ERR
                       "Failed to read valid processor max frequency as anchor 
point: %lu\n",
                       mul);
                return -EINVAL;
            }
            div = data->caps.highest_perf;
            res = (mul * perf * 1000) / div;

            if ( res > UINT_MAX || !res )
            {
                printk(XENLOG_ERR
                       "Frequeny exceeds maximum value UINT_MAX or being zero 
value: %lu\n",
                       res);
                return -EINVAL;
            }

            if ( lowest_freq && !(*lowest_freq) )
                *lowest_freq = (unsigned int)res;
            else
                *nominal_freq = (unsigned int)res;
        } while ( nominal_freq && !(*nominal_freq) );
    }

    return 0;
}
```

> In amd_cppc_khz_to_perf() you have a check to avoid division by zero. Why not
> the same safeguarding here?
>

div = data->caps.highest_perf; For highest_perf non-zero check, it is already 
added
in  amd_cppc_init_msrs()

> > +static int amd_get_max_freq(const struct amd_cppc_drv_data *data,
> > +                            unsigned int *max_freq) {
> > +    unsigned int nom_freq, boost_ratio;
> > +    int res;
> > +
> > +    res = amd_get_nominal_freq(data, &nom_freq);
> > +    if ( res )
> > +        return res;
> > +
> > +    boost_ratio = (unsigned int)(data->caps.highest_perf /
> > +                                 data->caps.nominal_perf);
>
> Similarly here - I can't spot what would prevent division by zero.
>

In amd_cppc_init_msrs(), before calculating the frequency, we have checked
all caps.xxx_perf info shall not be zero.
I'll complement check to avoid "highest_perf < nominal_perf", to ensure that
the calculation result of boost_ratio must not be zero.
```
    if ( data->caps.highest_perf == 0 || data->caps.lowest_perf == 0 ||
         data->caps.nominal_perf == 0 || data->caps.lowest_nonlinear_perf == 0 
||
         data->caps.lowest_perf > data->caps.lowest_nonlinear_perf ||
         data->caps.lowest_nonlinear_perf > data->caps.nominal_perf ||
         data->caps.nominal_perf > data->caps.highest_perf )
```

>
> Jan

Reply via email to