Hardware/CPU/AMD0FCPU.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 238 bddc6e01840a
child 344 3145aadca3d2
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
moel@14
     1
/*
moel@14
     2
  
moel@14
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@14
     4
moel@14
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@14
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@14
     7
  the License. You may obtain a copy of the License at
moel@14
     8
 
moel@14
     9
  http://www.mozilla.org/MPL/
moel@14
    10
moel@14
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@14
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@14
    13
  for the specific language governing rights and limitations under the License.
moel@14
    14
moel@14
    15
  The Original Code is the Open Hardware Monitor code.
moel@14
    16
moel@14
    17
  The Initial Developer of the Original Code is 
moel@14
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@14
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@14
    20
  the Initial Developer. All Rights Reserved.
moel@14
    21
moel@14
    22
  Contributor(s):
moel@14
    23
moel@14
    24
  Alternatively, the contents of this file may be used under the terms of
moel@14
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@14
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@14
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@14
    28
  of those above. If you wish to allow use of your version of this file only
moel@14
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@14
    30
  use your version of this file under the terms of the MPL, indicate your
moel@14
    31
  decision by deleting the provisions above and replace them with the notice
moel@14
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@14
    33
  the provisions above, a recipient may use your version of this file under
moel@14
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@14
    35
 
moel@14
    36
*/
moel@14
    37
paulwerelds@192
    38
using System;
moel@196
    39
using System.Globalization;
moel@196
    40
using System.Text;
paulwerelds@192
    41
using System.Threading;
paulwerelds@192
    42
moel@191
    43
namespace OpenHardwareMonitor.Hardware.CPU {
moel@196
    44
  internal sealed class AMD0FCPU : AMDCPU {
moel@196
    45
    
moel@195
    46
    private readonly Sensor[] coreTemperatures;
moel@195
    47
    private readonly Sensor[] coreClocks;
moel@195
    48
    private readonly Sensor busClock;
moel@14
    49
paulwerelds@192
    50
    private const uint FIDVID_STATUS = 0xC0010042;
moel@196
    51
moel@196
    52
    private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
moel@196
    53
    private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1103;
moel@14
    54
    private const uint THERMTRIP_STATUS_REGISTER = 0xE4;
moel@272
    55
    
moel@272
    56
    private readonly byte thermSenseCoreSelCPU0;
moel@272
    57
    private readonly byte thermSenseCoreSelCPU1;
moel@196
    58
    private readonly uint miscellaneousControlAddress;
moel@196
    59
moel@191
    60
    public AMD0FCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    61
      : base(processorIndex, cpuid, settings) 
moel@191
    62
    {
moel@77
    63
      float offset = -49.0f;
moel@63
    64
moel@63
    65
      // AM2+ 65nm +21 offset
moel@90
    66
      uint model = cpuid[0][0].Model;
moel@63
    67
      if (model >= 0x69 && model != 0xc1 && model != 0x6c && model != 0x7c) 
moel@63
    68
        offset += 21;
moel@63
    69
moel@272
    70
      if (model < 40) {
moel@272
    71
        // AMD Athlon 64 Processors
moel@272
    72
        thermSenseCoreSelCPU0 = 0x0;
moel@272
    73
        thermSenseCoreSelCPU1 = 0x4;
moel@272
    74
      } else {
moel@272
    75
        // AMD NPT Family 0Fh Revision F, G have the core selection swapped
moel@272
    76
        thermSenseCoreSelCPU0 = 0x4;
moel@272
    77
        thermSenseCoreSelCPU1 = 0x0;
moel@272
    78
      }
moel@272
    79
moel@90
    80
      // check if processor supports a digital thermal sensor 
moel@90
    81
      if (cpuid[0][0].ExtData.GetLength(0) > 7 && 
moel@90
    82
        (cpuid[0][0].ExtData[7, 3] & 1) != 0) 
moel@90
    83
      {
moel@90
    84
        coreTemperatures = new Sensor[coreCount];
moel@90
    85
        for (int i = 0; i < coreCount; i++) {
moel@90
    86
          coreTemperatures[i] =
moel@134
    87
            new Sensor("Core #" + (i + 1), i, SensorType.Temperature,
moel@195
    88
              this, new [] { new ParameterDescription("Offset [°C]", 
moel@90
    89
                  "Temperature offset of the thermal sensor.\n" + 
moel@90
    90
                  "Temperature = Value + Offset.", offset)
moel@165
    91
          }, settings);
moel@90
    92
        }
moel@90
    93
      } else {
moel@90
    94
        coreTemperatures = new Sensor[0];
moel@26
    95
      }
moel@24
    96
moel@196
    97
      miscellaneousControlAddress = GetPciAddress(
moel@196
    98
        MISCELLANEOUS_CONTROL_FUNCTION, MISCELLANEOUS_CONTROL_DEVICE_ID);
moel@14
    99
paulwerelds@192
   100
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
paulwerelds@192
   101
      coreClocks = new Sensor[coreCount];
paulwerelds@192
   102
      for (int i = 0; i < coreClocks.Length; i++) {
paulwerelds@193
   103
        coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
paulwerelds@193
   104
          this, settings);
moel@201
   105
        if (HasTimeStampCounter)
paulwerelds@192
   106
          ActivateSensor(coreClocks[i]);
paulwerelds@192
   107
      }
paulwerelds@192
   108
moel@14
   109
      Update();                   
moel@14
   110
    }
moel@14
   111
moel@191
   112
    protected override uint[] GetMSRs() {
moel@195
   113
      return new [] { FIDVID_STATUS };
moel@14
   114
    }
moel@14
   115
moel@196
   116
    public override string GetReport() {
moel@196
   117
      StringBuilder r = new StringBuilder();
moel@196
   118
      r.Append(base.GetReport());
moel@196
   119
moel@197
   120
      r.Append("Miscellaneous Control Address: 0x");
moel@196
   121
      r.AppendLine((miscellaneousControlAddress).ToString("X", 
moel@196
   122
        CultureInfo.InvariantCulture));
moel@196
   123
      r.AppendLine();
moel@196
   124
moel@196
   125
      return r.ToString();
moel@196
   126
    }
moel@196
   127
moel@110
   128
    public override void Update() {
moel@191
   129
      base.Update();
moel@191
   130
moel@236
   131
      if (miscellaneousControlAddress != Ring0.InvalidPciAddress) {
moel@42
   132
        for (uint i = 0; i < coreTemperatures.Length; i++) {
moel@236
   133
          if (Ring0.WritePciConfig(
moel@196
   134
            miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER,
moel@272
   135
            i > 0 ? thermSenseCoreSelCPU1 : thermSenseCoreSelCPU0)) {
moel@42
   136
            uint value;
moel@236
   137
            if (Ring0.ReadPciConfig(
moel@196
   138
              miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, 
moel@196
   139
              out value)) 
moel@196
   140
            {
moel@63
   141
              coreTemperatures[i].Value = ((value >> 16) & 0xFF) + 
moel@63
   142
                coreTemperatures[i].Parameters[0].Value;
moel@42
   143
              ActivateSensor(coreTemperatures[i]);
moel@42
   144
            } else {
moel@42
   145
              DeactivateSensor(coreTemperatures[i]);
moel@42
   146
            }
moel@24
   147
          }
moel@14
   148
        }
moel@24
   149
      }
paulwerelds@192
   150
moel@201
   151
      if (HasTimeStampCounter) {
paulwerelds@192
   152
        double newBusClock = 0;
paulwerelds@192
   153
paulwerelds@192
   154
        for (int i = 0; i < coreClocks.Length; i++) {
paulwerelds@192
   155
          Thread.Sleep(1);
paulwerelds@192
   156
paulwerelds@192
   157
          uint eax, edx;
moel@236
   158
          if (Ring0.RdmsrTx(FIDVID_STATUS, out eax, out edx,
moel@238
   159
            1UL << cpuid[i][0].Thread)) {
paulwerelds@192
   160
            // CurrFID can be found in eax bits 0-5, MaxFID in 16-21
paulwerelds@192
   161
            // 8-13 hold StartFID, we don't use that here.
paulwerelds@192
   162
            double curMP = 0.5 * ((eax & 0x3F) + 8);
paulwerelds@192
   163
            double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8);
moel@201
   164
            coreClocks[i].Value = 
moel@201
   165
              (float)(curMP * TimeStampCounterFrequency / maxMP);
moel@201
   166
            newBusClock = (float)(TimeStampCounterFrequency / maxMP);
paulwerelds@194
   167
          } else {
paulwerelds@194
   168
            // Fail-safe value - if the code above fails, we'll use this instead
moel@201
   169
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
paulwerelds@192
   170
          }
paulwerelds@192
   171
        }
paulwerelds@192
   172
paulwerelds@192
   173
        if (newBusClock > 0) {
paulwerelds@192
   174
          this.busClock.Value = (float)newBusClock;
paulwerelds@192
   175
          ActivateSensor(this.busClock);
paulwerelds@192
   176
        }
paulwerelds@192
   177
      }
moel@191
   178
    }  
moel@191
   179
 
moel@14
   180
  }
moel@14
   181
}