Hardware/CPU/AMD0FCPU.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 272 037a2d66082f
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2010 Michael Möller <mmoeller@openhardwaremonitor.org>
     8   Copyright (C) 2010 Paul Werelds <paul@werelds.net>
     9 
    10 */
    11 
    12 using System;
    13 using System.Globalization;
    14 using System.Text;
    15 using System.Threading;
    16 
    17 namespace OpenHardwareMonitor.Hardware.CPU {
    18   internal sealed class AMD0FCPU : AMDCPU {
    19     
    20     private readonly Sensor[] coreTemperatures;
    21     private readonly Sensor[] coreClocks;
    22     private readonly Sensor busClock;
    23 
    24     private const uint FIDVID_STATUS = 0xC0010042;
    25 
    26     private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
    27     private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1103;
    28     private const uint THERMTRIP_STATUS_REGISTER = 0xE4;
    29     
    30     private readonly byte thermSenseCoreSelCPU0;
    31     private readonly byte thermSenseCoreSelCPU1;
    32     private readonly uint miscellaneousControlAddress;
    33 
    34     public AMD0FCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
    35       : base(processorIndex, cpuid, settings) 
    36     {
    37       float offset = -49.0f;
    38 
    39       // AM2+ 65nm +21 offset
    40       uint model = cpuid[0][0].Model;
    41       if (model >= 0x69 && model != 0xc1 && model != 0x6c && model != 0x7c) 
    42         offset += 21;
    43 
    44       if (model < 40) {
    45         // AMD Athlon 64 Processors
    46         thermSenseCoreSelCPU0 = 0x0;
    47         thermSenseCoreSelCPU1 = 0x4;
    48       } else {
    49         // AMD NPT Family 0Fh Revision F, G have the core selection swapped
    50         thermSenseCoreSelCPU0 = 0x4;
    51         thermSenseCoreSelCPU1 = 0x0;
    52       }
    53 
    54       // check if processor supports a digital thermal sensor 
    55       if (cpuid[0][0].ExtData.GetLength(0) > 7 && 
    56         (cpuid[0][0].ExtData[7, 3] & 1) != 0) 
    57       {
    58         coreTemperatures = new Sensor[coreCount];
    59         for (int i = 0; i < coreCount; i++) {
    60           coreTemperatures[i] =
    61             new Sensor("Core #" + (i + 1), i, SensorType.Temperature,
    62               this, new [] { new ParameterDescription("Offset [°C]", 
    63                   "Temperature offset of the thermal sensor.\n" + 
    64                   "Temperature = Value + Offset.", offset)
    65           }, settings);
    66         }
    67       } else {
    68         coreTemperatures = new Sensor[0];
    69       }
    70 
    71       miscellaneousControlAddress = GetPciAddress(
    72         MISCELLANEOUS_CONTROL_FUNCTION, MISCELLANEOUS_CONTROL_DEVICE_ID);
    73 
    74       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
    75       coreClocks = new Sensor[coreCount];
    76       for (int i = 0; i < coreClocks.Length; i++) {
    77         coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
    78           this, settings);
    79         if (HasTimeStampCounter)
    80           ActivateSensor(coreClocks[i]);
    81       }
    82 
    83       Update();                   
    84     }
    85 
    86     protected override uint[] GetMSRs() {
    87       return new [] { FIDVID_STATUS };
    88     }
    89 
    90     public override string GetReport() {
    91       StringBuilder r = new StringBuilder();
    92       r.Append(base.GetReport());
    93 
    94       r.Append("Miscellaneous Control Address: 0x");
    95       r.AppendLine((miscellaneousControlAddress).ToString("X", 
    96         CultureInfo.InvariantCulture));
    97       r.AppendLine();
    98 
    99       return r.ToString();
   100     }
   101 
   102     public override void Update() {
   103       base.Update();
   104 
   105       if (miscellaneousControlAddress != Ring0.InvalidPciAddress) {
   106         for (uint i = 0; i < coreTemperatures.Length; i++) {
   107           if (Ring0.WritePciConfig(
   108             miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER,
   109             i > 0 ? thermSenseCoreSelCPU1 : thermSenseCoreSelCPU0)) {
   110             uint value;
   111             if (Ring0.ReadPciConfig(
   112               miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, 
   113               out value)) 
   114             {
   115               coreTemperatures[i].Value = ((value >> 16) & 0xFF) + 
   116                 coreTemperatures[i].Parameters[0].Value;
   117               ActivateSensor(coreTemperatures[i]);
   118             } else {
   119               DeactivateSensor(coreTemperatures[i]);
   120             }
   121           }
   122         }
   123       }
   124 
   125       if (HasTimeStampCounter) {
   126         double newBusClock = 0;
   127 
   128         for (int i = 0; i < coreClocks.Length; i++) {
   129           Thread.Sleep(1);
   130 
   131           uint eax, edx;
   132           if (Ring0.RdmsrTx(FIDVID_STATUS, out eax, out edx,
   133             1UL << cpuid[i][0].Thread)) {
   134             // CurrFID can be found in eax bits 0-5, MaxFID in 16-21
   135             // 8-13 hold StartFID, we don't use that here.
   136             double curMP = 0.5 * ((eax & 0x3F) + 8);
   137             double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8);
   138             coreClocks[i].Value = 
   139               (float)(curMP * TimeStampCounterFrequency / maxMP);
   140             newBusClock = (float)(TimeStampCounterFrequency / maxMP);
   141           } else {
   142             // Fail-safe value - if the code above fails, we'll use this instead
   143             coreClocks[i].Value = (float)TimeStampCounterFrequency;
   144           }
   145         }
   146 
   147         if (newBusClock > 0) {
   148           this.busClock.Value = (float)newBusClock;
   149           ActivateSensor(this.busClock);
   150         }
   151       }
   152     }  
   153  
   154   }
   155 }