From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755098AbbI2Bv7 (ORCPT ); Mon, 28 Sep 2015 21:51:59 -0400 Received: from mga01.intel.com ([192.55.52.88]:55102 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753712AbbI2Bv5 (ORCPT ); Mon, 28 Sep 2015 21:51:57 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,605,1437462000"; d="scan'208";a="779504747" Date: Tue, 29 Sep 2015 09:51:53 +0800 From: Haozhong Zhang To: Paolo Bonzini Cc: kvm@vger.kernel.org, Gleb Natapov , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org, Joerg Roedel , Wanpeng Li , Xiao Guangrong , Mihai =?utf-8?B?RG9uyJt1?= , Andy Lutomirski , Kai Huang , linux-kernel@vger.kernel.org Subject: Re: [PATCH 03/12] KVM: x86: Add a common TSC scaling function Message-ID: <20150929015153.GG3583@hzzhang-OptiPlex-9020.sh.intel.com> Mail-Followup-To: Paolo Bonzini , kvm@vger.kernel.org, Gleb Natapov , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org, Joerg Roedel , Wanpeng Li , Xiao Guangrong , Mihai =?utf-8?B?RG9uyJt1?= , Andy Lutomirski , Kai Huang , linux-kernel@vger.kernel.org References: <1443418691-24050-1-git-send-email-haozhong.zhang@intel.com> <1443418691-24050-4-git-send-email-haozhong.zhang@intel.com> <56099F35.1040106@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <56099F35.1040106@redhat.com> User-Agent: Mutt/1.5.23 (2014-03-12) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, Sep 28, 2015 at 10:12:37PM +0200, Paolo Bonzini wrote: > > > On 28/09/2015 07:38, Haozhong Zhang wrote: > > > > -static u64 __scale_tsc(u64 ratio, u64 tsc) > > -{ > > - u64 mult, frac, _tsc; > > - > > - mult = ratio >> 32; > > - frac = ratio & ((1ULL << 32) - 1); > > - > > - _tsc = tsc; > > - _tsc *= mult; > > - _tsc += (tsc >> 32) * frac; > > - _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32; > > - > > - return _tsc; > > -} > > This is basically > > return mul_u64_u64_shr(ratio, tsc, > kvm_tsc_scaling_ratio_frac_bits); > > except that Linux has no mul_u64_u64_shr function, only mul_u64_u32_shr. > > We should implement that function in include/linux/math64.h instead. > For the x86_64 case (or any other CONFIG_ARCH_SUPPORTS_INT128 > architecture) we can just write it directly, as is done already for > mul_u64_u32_shr. > > For the 32-bit case, here is an implementation of both the > multiplication and the shift, lifted from QEMU: > > static inline void mul64(uint64_t *lo, uint64_t *hi, > uint64_t a, uint64_t b) > { > typedef union { > uint64_t ll; > struct { > #ifdef __BIG_ENDIAN > uint32_t high, low; > #else > uint32_t low, high; > #endif > } l; > } LL; > LL rl, rm, rn, rh, a0, b0; > uint64_t c; > > a0.ll = a; > b0.ll = b; > > rl.ll = (uint64_t)a0.l.low * b0.l.low; > rm.ll = (uint64_t)a0.l.low * b0.l.high; > rn.ll = (uint64_t)a0.l.high * b0.l.low; > rh.ll = (uint64_t)a0.l.high * b0.l.high; > > c = (uint64_t)rl.l.high + rm.l.low + rn.l.low; > rl.l.high = c; > c >>= 32; > c = c + rm.l.high + rn.l.high + rh.l.low; > rh.l.low = c; > rh.l.high += (uint32_t)(c >> 32); > > *lo = rl.ll; > *hi = rh.ll; > } > > static inline void rshift128(uint64_t *lo, uint64_t *hi, int n) > { > uint64_t h; > if (!n) { > return; > } > h = *hi >> (n & 63); > if (n >= 64) { > *hi = 0; > *lo = h; > } else { > *lo = (*lo >> n) | (*hi << (64 - n)); > *hi = h; > } > } > > and you can easily reuse this code in Linux with just uintNN_t types > changed to uNN + some extra cleanups when it's placed in a single functions. > > Paolo Thanks! I'll add mul_u64_u64_shr() and replace __scale_tsc(). - Haozhong