1 Reply Latest reply on Aug 1, 2013 2:29 AM by allenchen

    How to get the values of on die digital thermal sensors for Atom D510?

    allenchen

      Hello experts,

      I want to monitor DTS measurements for Atom D510 on QNX. Thanks to MSangalli, he gave me an example codes (lists as following) using MSR which I think it is for CORE series CPU. So there are some more technical details need to be comfirmed here.

       

      1. what are the parameters for D510, 100C Tjunction_max? 0x19C for x86_msr_read() call?

       

      2. how to get values for each core?

       

      3. the sample codes can run OK. But the result prints that 100-th=100-84=16C, much different from BIOS monitoring result 58~64C. how to modify the codes for D510?

       

      Any suggestions are greatly appreciated!!

       

      Allen Chen

        • 1. Re: How to get the values of on die digital thermal sensors for Atom D510?
          allenchen

          The example codes list here.

           

          /*
          * msrsup.c
          *
          *  Created on: 25/lug/2013
          *      Author: MSangalli
          *
          * NOTES ABOUT CPU TEMPERATURES:
          * Intel defines a certain Tjunction temperature for the processor.
          * This value is usually in the range between 85癈 and 105癈.
          * In the later generation of processors, starting with Nehalem, the exact
          * Tjunction Max value is available for software to read in an MSR.
          * A different MSR contains the temperature data.
          * The data is represented as a Delta in 癈 between current temperature and Tjunction.
          * So the actual temperature is calculated like this 'Core Temp = Tjunction - Delta'
          * The size of the data field is 7 bits.
          * This means a Delta of 0 - 127癈 can be reported in theory.
          * In fact the reported temperature can rarely go below 0癈 and in some cases
          * (Core 2 - 45nm series) temperatures below 30?or even 40癈 are not reported.
          *
          * AMD processors report the temperature via a special register in the CPU's northbridge.
          * Core Temp reads the value from the register and uses a formula provided by AMD
          * to calculate the current temperature.
          * The formula for the Athlon 64 series, early Opterons and Semprons (K8 architecture) is:
          * 'Core Temp = Value - 49'.
          * For the newer generation of AMD processors like Phenom, Phenom II, newer Athlons,
          * Semprons and Opterons (K10 architecture and up), and their derivatives, there is a
          * different formula:
          * 'CPU Temp* = Value / 8'.
          * CPU Temp is because the Phenom\Opteron (K10) have only one sensor per package,
          * meaning there is only one reading per processor.
          *
          * VIA processors are capable of reporting the temperature of each core.
          * The thermal sensor provides an absolute temperature value in Celsius, there is
          * no need for any conversion or manipulation.
          * The Tjunction or TjMax temperature on VIA chips is usually between 70 and 90C.
          * 90C for the mobile and low power versions and 70C is for the desktop variants.
          */
          #include <stdio.h>
          #include <stdlib.h>
          #include <stdint.h>
          #include <unistd.h>
          #include <string.h>
          #include <errno.h>
          #include <err.h>
          #include <x86/priv.h>
          #include <sys/neutrino.h>

          /*
          * LOw WORD temperature into
          */
          typedef struct x86_term_info
          {
              uint32_t th_sts: 1;
              uint32_t th_sts_log: 1;
              uint32_t prochot_forcepr: 1;
              uint32_t prochot_forcepr_log: 1;
              uint32_t out_of_spec_sts: 1;
              uint32_t out_of_spec_sts_log: 1;
              uint32_t th_threshold_status1: 1;
              uint32_t th_threshold_status1_log: 1;
              uint32_t th_threshold_status2: 1;
              uint32_t th_threshold_status2_log: 1;
              uint32_t reserved0: 6;
              uint32_t dig_readout: 7;
              uint32_t rsv1: 4;
              uint32_t res_in_degrees_celsius: 4;
              uint32_t rd_valid: 1;
              uint32_t rsv2;
          }X86_TERM_T;

           

          typedef struct msr{
              struct sigevent        IntrEvent;
              intrspin_t               sLock;
              int                       IntrId;            // Int id
              int                       msrOp;            // Operation to do
              volatile uint32_t      reg_sel;        // msr Register index
              volatile uint64_t      val64;            // value to read/write
          }MSR_T;

           

          static MSR_T    lv_msr;

           


          static
          const struct sigevent* msr_irq(void* area, int size)
          {
              /*
               * rdmsr/wrmsr are privileged instruction that can be executed
               * only in the kernel space, so use the interrupt to do the work.
               */
              InterruptLock(&lv_msr.sLock );
              {
                  switch(lv_msr.msrOp)
                  {
                      default:{;}break;
                      case 1:{
                          // Read MSR register
                          if ( lv_msr.reg_sel )
                          {
                              lv_msr.val64 = rdmsr( lv_msr.reg_sel );
                              lv_msr.reg_sel = 0;
                          }
                      }break;

           

                      case 2:{
                          // Write MSR register
                          if ( lv_msr.reg_sel )
                          {
                              wrmsr( lv_msr.reg_sel, lv_msr.val64 );
                          }
                      }break;
                  }
                  lv_msr.msrOp  =0; //NOP
                  lv_msr.reg_sel=0;
              }InterruptUnlock( &lv_msr.sLock );
              return(&lv_msr.IntrEvent);
          }

           

          uint64_t x86_msr_read( uint32_t idx )
          {
              uint64_t  res;

           

              if(0 >= lv_msr.IntrId) return(-1);

           

              // Set command
              InterruptMask( 0, lv_msr.IntrId );
              {
                  InterruptLock( &lv_msr.sLock );
                  {
                      lv_msr.reg_sel= idx;
                      lv_msr.msrOp  =1;
                  }InterruptUnlock( &lv_msr.sLock );
              }InterruptUnmask( 0, lv_msr.IntrId );

           

              // Eventually, use a TimerTimeot here...
              /*********************************************/
              InterruptWait( 0, NULL );
              /*********************************************/

           

              // Read result
              InterruptMask( 0, lv_msr.IntrId );
              {
                  InterruptLock( &lv_msr.sLock );{
                      res = lv_msr.val64;
                  }InterruptUnlock( &lv_msr.sLock );
              }InterruptUnmask( 0, lv_msr.IntrId );
              return( res );
          }

           

          void x86_msr_write( uint32_t idx, uint64_t val )
          {
              if(0 >= lv_msr.IntrId) return;

           

              // Set command
              InterruptMask( 0, lv_msr.IntrId );{
                  InterruptLock( &lv_msr.sLock );{
                      lv_msr.val64= val;
                      lv_msr.reg_sel= idx;
                      lv_msr.msrOp  = 2;
                  }InterruptUnlock( &lv_msr.sLock );
              }InterruptUnmask( 0, lv_msr.IntrId );

           

              // Eventually, use a TimerTimeot here...
              /*********************************************/
              InterruptWait( 0, NULL );
              /*********************************************/
          }

           

          int x86_msr_init(void)
          {
              int res;

           

              SIGEV_INTR_INIT( &lv_msr.IntrEvent );
              if( 0 < (res= (InterruptAttach( 0, msr_irq, NULL, 0, 0 ))))
              {
                  lv_msr.IntrId=res;
              }
              return(res);
          }

           

          void x86_msr_close(void)
          {
              int intid;

           

              intid=lv_msr.IntrId;
              lv_msr.IntrId=0;
              if(0 >= intid) return;
              (void)InterruptDetach(intid);
          }

           

          void x86_print_cpu_temp(void)
          {
              union  {
                  X86_TERM_T    info;
                  uint64_t     temp;
              }x;
              int32_t th;
              int    j;

           

              // Intel CPU temp: Core Temp = Tjunction - Delta
               // This value is usually in the range between 85癈 and 105癈.
              // Check if Tjunsction is available in MSR register
              //
              for(j=0; j < 100; j++){
                  x.temp=x86_msr_read(0x19c);
                  if( x.info.rd_valid) break;  // temp is valid
              }
              printf("\nMSR[19C]: %08llx", x.temp);
              th = (x.info.dig_readout);
              printf(" C= %d@85/%d@105  +/-%d \n",85-th,105-th,  x.info.res_in_degrees_celsius );
          }

           

          int main(void)
          {

              ThreadCtl(_NTO_TCTL_IO, NULL);
              x86_msr_init();
              x86_print_cpu_temp();
              x86_msr_close();
          }