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