/* $Id: k10sensor.h 743 2012-06-18 06:10:35Z elkner $ */
#ifndef K10SENSOR_H
#define K10SENSOR_H
#include <sys/types.h>
#ifdef _KERNEL
#include <sys/ddi.h>
#include <sys/sunddi.h>
#else
#include <pciaccess.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define K10IOC ('k' << 24 | '1' << 16 | '0' << 8)
#define K10IOC_INFO (K10IOC | 1) /* get cpu_vars_t data. arg: *cpu_vars_t */
#define K10IOC_TCTRL (K10IOC | 2) /* get Tctrl. arg: *int32_t[2] */
#define K10IOC_RHTC (K10IOC | 3) /* refresh cached HTC settings */
#define K10IOC_RSTC (K10IOC | 4) /* refresh cached STC settings */
#define K10IOC_CONF (K10IOC | 5) /* re-fetch properties */
#ifdef _KERNEL
#define PCI_HDL ddi_acc_handle_t
#define PCI_GET32(dev,data,offset,fail_action_block) \
data = pci_config_get32(dev, offset);
#define PCI_PUT32(dev,data,offset,fail_action_block) \
pci_config_put32(dev, offset, data);
#else
#define PCI_HDL struct pci_device *
#define PCI_GET32(dev,data,offset,fail_action_block) \
if (pci_device_cfg_read_u32(dev, &data, offset)) fail_action_block
#define PCI_PUT32(dev,data,offset,fail_action_block) \
if (pci_device_cfg_write_u32(dev, data, offset)) fail_action_block
#endif
#define AMD_XFAMILY_MODEL(eax) (((eax) & 0x0fff0000) >> 16)
#define AMD_MODEL_STEPPING(eax) ((eax) & 0x000000ff)
/*
* Extracts bits from index h (high, inclusive) to l (low, inclusive) from
* u, which must be an unsigned integer.
*/
#define BITS(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
/* helper for cat_range_map */
struct cat_range {
/* the first xfamilyModel of the next generation, which doesn't belong to
* this category */
uint32_t nextFamilyModel;
/* the commonly use category name */
const char *name;
};
static const struct cat_range cat_range_map[] = {
{ 0x04, "Athlon64/Opteron" },
{ 0x10, "0Fh" },
{ 0x20, "10h" },
{ 0x30, "11h" },
{ 0x60, "12h/14h" },
{ 0x70, "15h" },
{ 0xfff + 1, "unknown" } /* max. possible val for xfamilyModel is 0xfff */
};
#define HTC_CAPABLE 0x01 /* Hardware Temperature Control capable flag */
#define HTC_THERMTRIP 0x02 /* thermtrip enabled flag */
#define LHTC_CAPABLE 0x04 /* Local HTC capable flag */
#define DC_0Fh 0x08 /* set if node is a family 0Fh DualCore */
#define TC_ENABLED 0x01 /* HTC/STC/LHTC enabled flag */
#define TC_SLEWED 0x02 /* control temperature slew controlled flag */
#define HTC 0 /* limit info index for HTC */
#define STC 1 /* limit info index for either STC (0Fh|10h) or LHTC (12h|14h)*/
/* temperature limit info. Only usable, if the TC_ENABLED flag is set */
typedef struct tc_limit {
/* state flags: see TC_*. */
uint32_t flags;
/* T control max. [1/1000 C]. INT32_MAX => n/a */
int32_t tcrit;
/* T_crit - T_hysteresis [1/1000 C]. INT32_MAX => n/a */
int32_t threshold;
} tc_limit_t;
/** Static information for a single CPU usually needed to query CPU states/info.
* Static means, once fully populated, there is no need to update its members
* as long as it is associated with the same CPU.
* eax and ebx refer to the corresponding values of the so named registers
* after a CPUID standard function call with eax=1. */
typedef struct cpu_vars {
/* the NodeId or CPU instance number */
uint32_t chipId;
/* BITX eax[27:16] */
uint32_t xfamilyModel;
/* BITX eax[7:0] */
uint32_t modelStepping;
/* the index for the category_range_map */
uint32_t catIdx;
/* CPUID ebx (we are interested in [31:27,15:0],only) */
uint32_t ebx;
/* silicon version of the chip. Usually populated by getSilicon() */
char revision[6];
/* HTC_* flags */
uint16_t flags;
/* if != 0, the relevant erratum # wrt. inaccurate temperature */
uint32_t erratum;
/* HTC, STC limits. NOTE: Can usually be modified by special software. */
tc_limit_t limits[2];
/* diode offset, which needs to be substracted from T control [1/1000 C]
* @see AMD Functional Data Sheet */
int32_t diode_offset;
/* t case max. [1/1000 C]. INT32_MAX => n/a */
int32_t t_case_max;
} cpu_vars_t;
/** Populate the index v->catIdx for the category_range_map based on
* v->xfamilyModel */
void fillCategoryIndex(cpu_vars_t *v);
/** Populate v->revision based on v->xfamilyModel and v->modelStepping */
void fillSiliconRevision(cpu_vars_t *v);
/** Checks, whether an "inaccurate temperature" erratum applies based on
* v->{xfamilyModel, modelStepping, ebx} */
void fillErratum(cpu_vars_t *v);
/** Populate v->{flags[HTC_THERMTRIP], t_case_max, diode_offset} from the
* Thermtrip register based on v->{xfamilyModel, modelStepping, revision, ebx}
*/
void fillThermtrip(PCI_HDL pci_hdl, cpu_vars_t *v);
/** Populate v->flags[HTC_CAPABLE,LHTC_CAPABLE,DC_0Fh] from the
* Northbridge Capabilities register based on v->{pci_hdl, xfamilyModel} */
void fillNBcapabilities(PCI_HDL pci_hdl, cpu_vars_t *v);
/** Populate v->limits[HTC] from the Hardware Thermal Control register based on
* v->{xfamilyModel, modelStepping, revision, ebx} */
void fillHtc(PCI_HDL pci_hdl, cpu_vars_t *v);
/** Populate v->limits[STC] from the Software or Local Hardware Thermal Control
* register based on v->{xfamilyModel, flags[HTC_CAPABLE,LHTC_CAPABLE]} */
void fillStc(PCI_HDL pci_hdl, cpu_vars_t *v);
/** Get the current control temperature based on
* v->{xfamilyModel, revision}. Returns 0 on error or if n/a */
int32_t getControlTemp(PCI_HDL pci_hdl, cpu_vars_t *v, boolean_t core1);
/** Append v data as a human readable string to buf */
char *dumpCpuInfo(char *buf, cpu_vars_t *v);
/** Append T control value(s) as a human readable string to buf */
char *dumpTctrl(char *buf, PCI_HDL pci_hdl, cpu_vars_t *v);
#ifdef __cplusplus
}
#endif
#endif /* K10TEMP_H */