qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 4/4] smbus: Fix spd_data_generate() for number of banks > 2


From: Markus Armbruster
Subject: Re: [PATCH 4/4] smbus: Fix spd_data_generate() for number of banks > 2
Date: Tue, 21 Apr 2020 06:57:13 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux)

BALATON Zoltan <address@hidden> writes:

> On Mon, 20 Apr 2020, Markus Armbruster wrote:
>> spd_data_generate() splits @ram_size bytes into @nbanks RAM banks of
>> 1 << sz_log2 MiB each, like this:
>>
>>    size = ram_size >> 20; /* work in terms of megabytes */
>>    [...]
>>    nbanks = 1;
>>    while (sz_log2 > max_log2 && nbanks < 8) {
>>        sz_log2--;
>>        nbanks++;
>>    }
>>
>> Each iteration halves the size of a bank, and increments the number of
>> banks.  Wrong: it should double the number of banks.
>
> Hmm, why? SPD data has: spd[5]: Number of RAM banks on module (1–255)
> (and for DDR2: Ranks-1 (0–7)). So nothing says it has to be power of 2
> even if it's commonly 2 or 4. Does this break anything that needs this
> to be power of 2? Otherwise I thik this change is wrong.

Yes, SPD data does not require the number of banks to be a power of two.
But that's not why the loop above is wrong.  To see, let's execute it on
e-paper for type = SDR (thus max_log2 = 9) and ram_size = 2048 MiB:

    iteration   sz_log2  nbanks  bank size  total size
    0           11       1       2048 MiB   2048 MiB
    1           10       2       1024 MiB   2048 MiB
    2            9       3        512 MiB   1536 MiB    Oops!

The loop is wrong, because it fails to maintain its invariant

    nbanks * (1ull << sz_log2) == size

If you ever need magic to come up with nbanks that aren't powers of two,
you'll have to replace this loop.

But I'd rip it out instead, and ...

>> The bug goes back all the way to commit b296b664ab "smbus: Add a
>> helper to generate SPD EEPROM data".
>>
>> It can't bite because spd_data_generate()'s current users pass only
>> @ram_size that result in *zero* iterations:
>>
>>    machine     RAM size    #banks  type    bank size
>>    fulong2e     256 MiB         1   DDR      256 MiB
>>    sam460ex    2048 MiB         1   DDR2    2048 MiB
>>                1024 MiB         1   DDR2    1024 MiB
>>                 512 MiB         1   DDR2     512 MiB
>>                 256 MiB         1   DDR2     256 MiB
>>                 128 MiB         1   SDR      128 MiB
>>                  64 MiB         1   SDR       64 MiB
>>                  32 MiB         1   SDR       32 MiB
>>
>> Apply the obvious, minimal fix.  I admit I'm tempted to rip out the
>> unused (and obviously untested) feature instead, because YAGNI.

... have the board code pass the number of banks.

>> Note that this is not the final result, as spd_data_generate() next
>> increases #banks from 1 to 2 if possible.  This is done "to avoid a
>> bug in MIPS Malta firmware".  We don't even use this function with
>> machine type malta.  *Shrug*
>
> The code that is generalised here is originally from MIPS Malta and
> the idea was to change that as well to use this but nobody did that so
> far.
>
> Regards,
> BALATON Zoltan
>
>> Signed-off-by: Markus Armbruster <address@hidden>
>> ---
>> hw/i2c/smbus_eeprom.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
>> index 07fbbf87f1..e199fc8678 100644
>> --- a/hw/i2c/smbus_eeprom.c
>> +++ b/hw/i2c/smbus_eeprom.c
>> @@ -229,7 +229,7 @@ uint8_t *spd_data_generate(enum sdram_type type, 
>> ram_addr_t ram_size)
>>     nbanks = 1;
>>     while (sz_log2 > max_log2 && nbanks < 8) {
>>         sz_log2--;
>> -        nbanks++;
>> +        nbanks *= 2;
>>     }
>>
>>     assert(size == (1ULL << sz_log2) * nbanks);
>>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]