diff options
Diffstat (limited to 'kernel/bar_emulation.c')
| -rw-r--r-- | kernel/bar_emulation.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/kernel/bar_emulation.c b/kernel/bar_emulation.c index 8e3f8cf..d1702c8 100644 --- a/kernel/bar_emulation.c +++ b/kernel/bar_emulation.c @@ -290,13 +290,24 @@ int nv_vgpu_bar_emul_init(struct nv_vgpu_device *vgpu) * guest's fbSize - reserved arithmetic stays consistent. */ u64 fb = nv_vgpu_fb_emul_size(ctx->vgpu); - u32 scale = 0; + u32 scale = 0, mag; + /* + * Find the largest SCALE whose MAG fits the 6-bit field, then + * canonicalise: strip factors of two from MAG while SCALE can + * absorb them. 512 MiB -> mag=1,scale=9 -> 0x19 (the historical + * known-good value); 1 GiB -> 0x1a; 2 GiB -> 0x1b. Sizes that + * are not exactly representable round down. + */ while (scale < 15 && (fb >> (scale + 20)) > 0x3f) scale++; + mag = (u32)(fb >> (scale + 20)); + while (scale < 15 && mag > 1 && !(mag & 1u)) { + mag >>= 1; + scale++; + } *(u32 *)((u8 *)ctx->bar0_shadow + 0x100ce0) = - ((((u32)(fb >> (scale + 20))) & 0x3f) << 4) | - (scale & 0xf); + ((mag & 0x3f) << 4) | (scale & 0xf); } /* |
