Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Oct 2013 05:24:41 +0400
From:      rozhuk.im@gmail.com
To:        <hackers@freebsd.org>
Subject:   amdtemp need help with testing
Message-ID:  <52520d5f.c402cd0a.5f4e.ffffffa2@mx.google.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

------=_NextPart_000_0206_01CEC31D.875A19E0
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: 7bit

I updated amdtemp and now I need your help with testing.

Now the driver should support all AMD processors.
For a family of 15h and 16h, not all sensors are available - for my system
does not find drivers for ati SMBus, and other systems based on the AMD I
have not.



------=_NextPart_000_0206_01CEC31D.875A19E0
Content-Type: text/plain;
	name="amdtemp.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="amdtemp.c"

/*-=0A=
 * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>=0A=
 * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>=0A=
 * Copyright (c) 2009-2011 Jung-uk Kim <jkim@FreeBSD.org>=0A=
 * Copyright (c) 2013 Rozhuk Ivan <rozhuk.im@gmail.com>=0A=
 * All rights reserved.=0A=
 *=0A=
 * Redistribution and use in source and binary forms, with or without=0A=
 * modification, are permitted provided that the following conditions=0A=
 * are met:=0A=
 * 1. Redistributions of source code must retain the above copyright=0A=
 *    notice, this list of conditions and the following disclaimer.=0A=
 * 2. Redistributions in binary form must reproduce the above copyright=0A=
 *    notice, this list of conditions and the following disclaimer in the=0A=
 *    documentation and/or other materials provided with the =
distribution.=0A=
 *=0A=
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR=0A=
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED=0A=
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE=0A=
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,=0A=
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES=0A=
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR=0A=
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0A=
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,=0A=
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING =
IN=0A=
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE=0A=
 * POSSIBILITY OF SUCH DAMAGE.=0A=
 */=0A=
=0A=
/*=0A=
 * Driver for the AMD CPU on-die thermal sensors.=0A=
 * Initially based on the k8temp Linux driver.=0A=
 */=0A=
=0A=
#include <sys/cdefs.h>=0A=
__FBSDID("$FreeBSD$");=0A=
=0A=
#include <sys/param.h>=0A=
#include <sys/systm.h>=0A=
#include <sys/kernel.h>=0A=
#include <sys/module.h>=0A=
#include <sys/bus.h>=0A=
#include <sys/resource.h>=0A=
#include <sys/rman.h>=0A=
#include <sys/sysctl.h>=0A=
#include <sys/lock.h>=0A=
#include <sys/mutex.h>=0A=
=0A=
#include <machine/bus.h>=0A=
#include <machine/resource.h>=0A=
#include <machine/md_var.h>=0A=
#include <machine/specialreg.h>=0A=
#include <machine/cputypes.h>=0A=
=0A=
#include <dev/pci/pcivar.h>=0A=
=0A=
#if defined(__FreeBSD_version) && (__FreeBSD_version < 999999)=0A=
/* XXX */=0A=
extern uint32_t	pci_cfgregread(int, int, int, int, int);=0A=
#endif=0A=
=0A=
=0A=
struct amdtemp_softc {=0A=
	device_t		dev;=0A=
	struct mtx		lock; /* Read/write lock for some registers. */=0A=
	uint32_t		cpu_ncores;=0A=
	uint32_t		flags;=0A=
	uint32_t		tts_flags; /* Thermaltrip Status flags. */=0A=
	int32_t			tts_temp_offset[4];=0A=
	int32_t			rtc_temp_offset;=0A=
	int32_t			tsi_temp_offset[8];=0A=
	struct sysctl_oid	*sysctl_cpu[MAXCPU]; /* dev.cpu.X.temperature oids. */=0A=
	struct intr_config_hook	sc_ich;=0A=
};=0A=
#define	AMDTEMP_F_TTS		1	/* Thermaltrip Status. */=0A=
#define	AMDTEMP_F_RTC		2	/* Reported Temperature Control. */=0A=
#define	AMDTEMP_F_TSI		4	/* TSI via CPU registers. */=0A=
#define	AMDTEMP_F_SBTSI		8	/* TSI via SMBus. */=0A=
=0A=
#define	AMDTEMP_TTS_F_CS_SWAP	0x01	/* ThermSenseCoreSel is inverted. */=0A=
#define	AMDTEMP_TTS_F_CT_10BIT	0x02	/* CurTmp is 10-bit wide. */=0A=
#define	AMDTEMP_TTS_F_OFF28	0x04	/* CurTmp starts at -28C. */=0A=
=0A=
=0A=
#define	AMDTEMP_LOCK(sc)	mtx_lock(&(sc)->lock)=0A=
#define	AMDTEMP_UNLOCK(sc)	mtx_unlock(&(sc)->lock)=0A=
=0A=
=0A=
/* CPU Family/Model Register */=0A=
#define	AMD_REG_CPUID		0xfc=0A=
=0A=
/* =0A=
 * Thermaltrip Status Register=0A=
 * BIOS and Kernel Developer=E2=80=99s Guide for AMD NPT Family 0Fh =
Processors=0A=
 * 32559 Rev. 3.16 November 2009=0A=
 */=0A=
/* D18F3xE4 Thermtrip Status Register */=0A=
#define	AMD_REG_THERMTRIP_STAT	0xe4=0A=
union reg_amd_thermtrip_status_desc {=0A=
	uint32_t u32;=0A=
	struct reg_amd_thermtrip_status_bits {=0A=
		uint32_t r0:1;		/* 0 Reserved. */=0A=
		uint32_t Thermtp:1;	/* 1 ro The processor has entered the THERMTRIP =
state. */=0A=
		uint32_t ThermSenseCoreSel:1; /* 2 rw  */=0A=
		uint32_t ThermtpSense0:1; /* 3 ro  */=0A=
		uint32_t ThermtpSense1:1; /* 4 ro  */=0A=
		uint32_t ThermtpEn:1;	/* 5 ro The THERMTRIP state is supported by the =
processor. */=0A=
		uint32_t ThermSenseSel:1; /* 6 rw  */=0A=
		uint32_t r1:1;		/* 7 Reserved. */=0A=
		uint32_t DiodeOffset:6;	/* 13:8 ro Thermal diode offset is used to =
correct the measurement made by an external temperature sensor. */=0A=
		uint32_t CurTmp:10;	/* 23:14 ro This field returns the current value =
of the internal thermal sensor. */=0A=
		uint32_t TjOffset:5;	/* 28:24 ro This field is the offset from CurTmp =
used to normalize to Tcontrol. */=0A=
		uint32_t r2:2;		/* 30:29 Reserved. */=0A=
		uint32_t SwThermtp:1;	/* 31 rw  */=0A=
	} __packed bits;=0A=
};=0A=
=0A=
=0A=
/* DRAM Configuration High Register */=0A=
#define	AMD_REG_DRAM_CONF_HIGH	0x94	/* Function 2 */=0A=
#define	AMD_REG_DRAM_MODE_DDR3	0x0100=0A=
=0A=
/* D18F3xA4 Reported Temperature Control Register */=0A=
#define	AMD_REG_REPTMP_CTRL	0xa4=0A=
union reg_amd_rep_tmp_ctrl_desc {=0A=
	uint32_t u32;=0A=
	struct reg_amd_rep_tmp_ctrl_bits {=0A=
		uint32_t PerStepTimeUp:5; /* 4:0 rw per 1/8th step time up. */=0A=
		uint32_t TmpMaxDiffUp:2;/* 6:5 rw temperature maximum difference up. */=0A=
		uint32_t TmpSlewDnEn:1;	/* 7 rw temperature slew downward enable. */=0A=
		uint32_t PerStepTimeDn:5;/* 12:8 rw per 1/8th step time down. */=0A=
		uint32_t r0:3;		/* 15:13 Reserved. */=0A=
		uint32_t CurTmpTjSel:2;	/* 17:16 rw Current temperature select. */=0A=
		uint32_t r1:3;		/* 20:18 Reserved. */=0A=
		uint32_t CurTmp:11;	/* 31:21 ro/rw current temperature. */=0A=
	} __packed bits;=0A=
};=0A=
/* CurTmpTjSel valid family 10h, 15h, 16h processors. */=0A=
=0A=
=0A=
/* SB-TSI */=0A=
#define AMD_REG_SBI_CTRL	0x1e4 /* SBI Control */=0A=
union reg_amd_sbi_ctrl_desc {=0A=
	uint32_t u32;=0A=
	struct reg_amd_sbi_ctrl_bits {=0A=
		uint32_t r0:1;		/* 0 Reserved. */=0A=
		uint32_t SbRmiDis:1;	/* 1 ro SMBus-based sideband remote management =
interface disable. */=0A=
		uint32_t r1:1;		/* 2 Reserved. */=0A=
		uint32_t SbTsiDis:1;	/* 3 ro SMBus-based sideband temperature sensor =
interface disable. */=0A=
		uint32_t SbiAddr:3;	/* 6:4 rw SMBus-based sideband interface address. =
*/=0A=
		uint32_t r2:1;		/* 7 Reserved. */=0A=
		uint32_t LvtOffset:4;	/* 11:8 rw local vector table offset. */=0A=
		uint32_t r3:19;		/* 30:12 Reserved. */=0A=
		uint32_t SbiRegWrDn:1;	/* 31 ro SBI register write complete. */=0A=
	} __packed bits;=0A=
};=0A=
/*=0A=
 * AMD Family 10h Processor BKDG: SbRmiDis (bit offset: 1) + SbTsiDis =
(bit offset: 3)=0A=
 * AMD Family 11h Processor BKDG: SbTsiDis (bit offset: 1)=0A=
 * AMD Family 12h Processor BKDG: SbTsiDis (bit offset: 1)=0A=
 * BKDG for AMD Family 14h Models 00h-0Fh Processors: SbTsiDis (bit =
offset: 1)=0A=
 * BKDG for AMD Family 15h Models 00h-0Fh Processors: SbRmiDis, no TSI=0A=
 * BKDG for AMD Family 16h Models 00h-0Fh Processors: ??? 48751 Rev 3.00 =
- May 30, 2013=0A=
 */=0A=
#define AMD_REG_SBI_ADDR	0x1e8 /* SBI Address */=0A=
#define AMD_REG_SBI_ADDR_MASK	0x07=0A=
#define AMD_REG_SBI_DATA	0x1ec /* SBI Data */=0A=
#define AMD_SBI_WRITE_TIMEOUT	100 /* XXX should be increased? */=0A=
=0A=
/* SB-TSI registers. */=0A=
#define SB_TSI_REG_CPU_TEMP_HB		0x01 /* CPU Temperature High Byte =
Register. */=0A=
#define SB_TSI_REG_STATUS		0x02 /* SB-TSI Status Register. */=0A=
#define SB_TSI_REG_CFG			0x03 /* SB-TSI Configuration Register. */=0A=
#define SB_TSI_REG_UPD_RATE		0x04 /* Update Rate Register. */=0A=
#define SB_TSI_REG_HIGH_TEMP_THB	0x07 /* High Temperature Threshold High =
Byte Register. */=0A=
#define SB_TSI_REG_LOW_TEMP_THB		0x08 /* Low Temperature Threshold High =
Byte Register.*/=0A=
#define SB_TSI_REG_CFG2			0x09 /* SB-TSI Configuration Register. */=0A=
#define SB_TSI_REG_CPU_TEMP_LB		0x10 /* CPU Temperature Low Byte =
Register. */=0A=
#define SB_TSI_REG_CPU_TEMP_OFF_HB	0x11 /* CPU Temperature Offset High =
Byte Register. */=0A=
#define SB_TSI_REG_CPU_TEMP_OFF_LB	0x12 /* CPU Temperature Offset Low =
Byte Register. */=0A=
#define SB_TSI_REG_HIGH_TEMP_TLB	0x13 /* High Temperature Threshold Low =
Byte Register. */=0A=
#define SB_TSI_REG_LOW_TEMP_TLB		0x14 /* Low Temperature Threshold Low =
Byte Register. */=0A=
#define SB_TSI_REG_TIMEOUT_CFG		0x22 /* Timeout Configuration Register. =
*/=0A=
#define SB_TSI_REG_ALERT_THRESHOLD	0x32 /* Alert Threshold Register. */=0A=
#define SB_TSI_REG_ALERT_CFG		0xbf /* Alert Configuration Register. */=0A=
#define SB_TSI_REG_MANUFACTURE_ID	0xfe /* Manufacture ID Register. */=0A=
#define SB_TSI_REG_REVISION		0xff /* SB-TSI Revision Register. */=0A=
=0A=
=0A=
=0A=
#define	AMDTEMP_ZERO_C_TO_K	2732=0A=
=0A=
=0A=
#define ARG2_GET_REG(arg)	((arg) & 0xffff)=0A=
#define ARG2_GET_A1(arg)	(((arg) >> 16) & 0xff)=0A=
#define ARG2_GET_A2(arg)	(((arg) >> 24) & 0xff)=0A=
#define MAKE_ARG2(reg, a1, a2)				\=0A=
    (((reg) & 0xff) | (((a1) & 0xff) << 16) | (((a2) & 0xff) << 24))=0A=
=0A=
struct amdtemp_sysctl_reg {=0A=
	uint16_t	reg;=0A=
	uint8_t		a1;=0A=
	uint8_t		a2;=0A=
	uint32_t	flags;=0A=
	char		*fmt;=0A=
	int 		(*oid_handler)(SYSCTL_HANDLER_ARGS);=0A=
	char		*name;=0A=
	char		*descr;=0A=
};=0A=
=0A=
static void	amdtemp_sysctl_reg_add(struct amdtemp_softc *sc,=0A=
		    struct sysctl_oid_list *child, struct amdtemp_sysctl_reg *regs);=0A=
static void	amdtemp_sysctl_reg_add2(struct amdtemp_softc *sc,=0A=
		    struct sysctl_oid_list *child, struct amdtemp_sysctl_reg *regs,=0A=
		    uint32_t a2);=0A=
static int	amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS);=0A=
=0A=
static uint32_t	amdtemp_tts_get_temp(struct amdtemp_softc *sc, uint32_t =
reg,=0A=
		    uint8_t core, uint8_t sense);=0A=
static int	amdtemp_tts_temp_reg_sysctl(SYSCTL_HANDLER_ARGS);=0A=
=0A=
static int	amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS);=0A=
=0A=
static void	amdtemp_sbi_set_addr(struct amdtemp_softc *sc, uint32_t =
sbi_addr);=0A=
static uint32_t	amdtemp_sbi_read(struct amdtemp_softc *sc, uint32_t =
sbi_addr,=0A=
		    uint32_t reg_addr);=0A=
static int	amdtemp_sbi_write(struct amdtemp_softc *sc, uint32_t sbi_addr,=0A=
		    uint32_t reg_addr, uint8_t data);=0A=
static int	amdtemp_tsi_reg_sysctl(SYSCTL_HANDLER_ARGS);=0A=
static int	amdtemp_tsi_temp_reg_sysctl(SYSCTL_HANDLER_ARGS);=0A=
=0A=
=0A=
/* D18F3xE4 Thermtrip Status Register */=0A=
static struct amdtemp_sysctl_reg amdtemp_thermtrip_status_reg_bits[] =3D =
{=0A=
	{ AMD_REG_THERMTRIP_STAT, 24, 5, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "TjOffset", "This field is the offset from =
CurTmp used to normalize to Tcontrol." },=0A=
	{ AMD_REG_THERMTRIP_STAT,  8, 6, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "DiodeOffset", "Thermal diode offset is used to =
correct the measurement made by an external temperature sensor." },=0A=
	{ AMD_REG_THERMTRIP_STAT,  5, 1, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "ThermtpEn", "The THERMTRIP state is supported =
by the processor." },=0A=
	{ AMD_REG_THERMTRIP_STAT,  1, 1, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "Thermtrip", "The processor has entered the =
THERMTRIP state." },=0A=
=0A=
	{ 0, 0, 0, 0, NULL, NULL, NULL, NULL }=0A=
};=0A=
=0A=
/* D18F3xA4 Reported Temperature Control Register */=0A=
static struct amdtemp_sysctl_reg amdtemp_reptmp_reg_bits[] =3D {=0A=
	{ AMD_REG_REPTMP_CTRL, 21,11, (CTLFLAG_RD | CTLTYPE_INT), "IK", =
amdtemp_rtc_temp_sysctl, "CurTmp", "Provides the current control =
temperature, Tctl, after the slew-rate controls have been applied." },=0A=
	{ AMD_REG_REPTMP_CTRL, 16, 2, (CTLFLAG_RW | CTLTYPE_INT), "IK", =
amdtemp_rtc_temp_sysctl, "CurTmpTjSel", "Specifies a value used to =
create Tctl." },=0A=
	{ AMD_REG_REPTMP_CTRL,  7, 1, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "TmpSlewDnEn", "Temperature slew downward =
enable." },=0A=
	{ AMD_REG_REPTMP_CTRL,  5, 2, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "TmpMaxDiffUp", "Specifies the maximum =
difference, (Tctlm - Tctl), when Tctl immediatly updates to Tctlm." },=0A=
	{ AMD_REG_REPTMP_CTRL,  8, 5, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "PerStepTimeDn", "Specifies the time that Tctlm =
must remain below Tctl before applying a 0.125 downward step." },=0A=
	{ AMD_REG_REPTMP_CTRL,  0, 5, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_sysctl_reg_bits, "PerStepTimeUp", "Specifies the time that Tctlm =
must remain above Tctl before applying a 0.125 upward step." },=0A=
=0A=
	{ 0, 0, 0, 0, NULL, NULL, NULL, NULL }=0A=
};=0A=
=0A=
/* SB-TSI registers. */=0A=
static struct amdtemp_sysctl_reg amdtemp_tsi_regs[] =3D {=0A=
	{ SB_TSI_REG_CPU_TEMP_LB, SB_TSI_REG_CPU_TEMP_HB, 0, (CTLFLAG_RD | =
CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, "cpu_temperature", "CPU =
Temperature" },=0A=
	{ SB_TSI_REG_HIGH_TEMP_TLB, SB_TSI_REG_HIGH_TEMP_THB, 0, (CTLFLAG_RD | =
CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, =
"high_temperature_threshold", "High Temperature Threshold" },=0A=
	{ SB_TSI_REG_LOW_TEMP_TLB, SB_TSI_REG_LOW_TEMP_THB, 0, (CTLFLAG_RD | =
CTLTYPE_INT), "IK", amdtemp_tsi_temp_reg_sysctl, =
"low_temperature_threshold", "Low Temperature Threshold" },=0A=
=0A=
	{ SB_TSI_REG_CPU_TEMP_OFF_HB, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "cpu_temperature_offset_hi", "CPU Temperature =
Offset High Byte" },=0A=
	{ SB_TSI_REG_CPU_TEMP_OFF_LB, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "cpu_temperature_offset_lo", "CPU Temperature =
Offset Low Byte" },=0A=
=0A=
	{ SB_TSI_REG_STATUS, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "status", "SB-TSI Status" },=0A=
	{ SB_TSI_REG_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "cfg3", "SB-TSI Configuration Register 0x03" },=0A=
	{ SB_TSI_REG_CFG2, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "cfg9", "SB-TSI Configuration Register 0x09" },=0A=
	{ SB_TSI_REG_UPD_RATE, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "upd_rate", "Update Rate" },=0A=
	{ SB_TSI_REG_TIMEOUT_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "timeout_cfg", "Timeout Configuration" },=0A=
	{ SB_TSI_REG_ALERT_THRESHOLD, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "alert_threshold", "Alert Threshold" },=0A=
	{ SB_TSI_REG_ALERT_CFG, 0, 0, (CTLFLAG_RW | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "alert_cfg", "Alert Configuration" },=0A=
	{ SB_TSI_REG_MANUFACTURE_ID, 0, 0, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "manufacture_id", "Manufacture ID" },=0A=
	{ SB_TSI_REG_REVISION, 0, 0, (CTLFLAG_RD | CTLTYPE_UINT), "IU", =
amdtemp_tsi_reg_sysctl, "revision", "SB-TSI Revision" },=0A=
=0A=
	{ 0, 0, 0, 0, NULL, NULL, NULL, NULL }=0A=
};=0A=
=0A=
=0A=
/*=0A=
 * Device methods.=0A=
 */=0A=
static void 	amdtemp_identify(driver_t *driver, device_t parent);=0A=
static int	amdtemp_probe(device_t dev);=0A=
static int	amdtemp_attach(device_t dev);=0A=
static int	amdtemp_detach(device_t dev);=0A=
static void	amdtemp_intrhook(void *arg);=0A=
=0A=
=0A=
static device_method_t amdtemp_methods[] =3D {=0A=
	/* Device interface */=0A=
	DEVMETHOD(device_identify,	amdtemp_identify),=0A=
	DEVMETHOD(device_probe,		amdtemp_probe),=0A=
	DEVMETHOD(device_attach,	amdtemp_attach),=0A=
	DEVMETHOD(device_detach,	amdtemp_detach),=0A=
=0A=
	DEVMETHOD_END=0A=
};=0A=
=0A=
static driver_t amdtemp_driver =3D {=0A=
	"amdtemp",=0A=
	amdtemp_methods,=0A=
	sizeof(struct amdtemp_softc),=0A=
};=0A=
static devclass_t amdtemp_devclass;=0A=
DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, =
NULL);=0A=
MODULE_VERSION(amdtemp, 1);=0A=
=0A=
=0A=
=0A=
static void=0A=
amdtemp_identify(driver_t *driver, device_t parent) {=0A=
	device_t child;=0A=
	uint32_t cpuid, model;=0A=
=0A=
	/* Make sure we're not being doubly invoked. */=0A=
	if (device_find_child(parent, "amdtemp", -1) !=3D NULL)=0A=
		return;=0A=
	/* AMD processors only. */=0A=
	if (CPU_VENDOR_AMD !=3D pci_get_vendor(parent))=0A=
		return;=0A=
	/* Is processor supported? */=0A=
	cpuid =3D pci_read_config(parent, AMD_REG_CPUID, 4);=0A=
	switch (CPUID_TO_FAMILY(cpuid)) {=0A=
	case 0x0f:=0A=
		model =3D CPUID_TO_MODEL(cpuid);=0A=
		if ((model =3D=3D 0x04 && (cpuid & CPUID_STEPPING) =3D=3D 0) ||=0A=
		    (model =3D=3D 0x05 && (cpuid & CPUID_STEPPING) <=3D 1))=0A=
			return;=0A=
		break;=0A=
	case 0x10:=0A=
	case 0x11:=0A=
	case 0x12:=0A=
	case 0x14:=0A=
	case 0x15:=0A=
	case 0x16:=0A=
		break;=0A=
	default:=0A=
		return;=0A=
	}=0A=
	/* Ok! */=0A=
	child =3D device_add_child(parent, "amdtemp", -1);=0A=
	if (child =3D=3D NULL)=0A=
		device_printf(parent, "add amdtemp child failed\n");=0A=
}=0A=
=0A=
static int=0A=
amdtemp_probe(device_t dev) {=0A=
=0A=
	if (resource_disabled("amdtemp", 0))=0A=
		return (ENXIO);=0A=
=0A=
	device_set_desc(dev, "AMD CPU On-Die Thermal Sensors");=0A=
=0A=
	return (BUS_PROBE_GENERIC);=0A=
}=0A=
=0A=
static int=0A=
amdtemp_attach(device_t dev) {=0A=
	struct amdtemp_softc *sc =3D device_get_softc(dev);=0A=
	uint32_t i, cpuid, model;=0A=
	union reg_amd_sbi_ctrl_desc reg_ctrl;=0A=
	struct sysctl_ctx_list *ctx =3D device_get_sysctl_ctx(dev);=0A=
	struct sysctl_oid_list *child =3D =
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), *list;=0A=
	struct sysctl_oid *node, *sub_node;=0A=
	char str[32];=0A=
	int erratum319 =3D 0;=0A=
	u_int regs[4], bid;=0A=
=0A=
	sc->dev =3D dev;=0A=
	/* Find number of cores per package. */=0A=
	sc->cpu_ncores =3D (((amd_feature2 & AMDID2_CMP) !=3D 0) ?=0A=
	    ((cpu_procinfo2 & AMDID_CMP_CORES) + 1) : 1);=0A=
	if (sc->cpu_ncores > MAXCPU)=0A=
		return (ENXIO);=0A=
	mtx_init(&sc->lock, device_get_nameunit(dev), "amdtemp", MTX_DEF);=0A=
=0A=
	cpuid =3D pci_read_config(dev, AMD_REG_CPUID, 4);=0A=
	model =3D CPUID_TO_MODEL(cpuid);=0A=
	switch (CPUID_TO_FAMILY(cpuid)) {=0A=
	case 0x0f:=0A=
		/*=0A=
		 * Thermaltrip Status Register=0A=
		 *=0A=
		 * - ThermSenseCoreSel=0A=
		 *=0A=
		 * Revision F & G:	0 - Core1, 1 - Core0=0A=
		 * Other:		0 - Core0, 1 - Core1=0A=
		 *=0A=
		 * - CurTmp=0A=
		 *=0A=
		 * Revision G:		bits 23-14=0A=
		 * Other:		bits 23-16=0A=
		 *=0A=
		 * XXX According to the BKDG, CurTmp, ThermSenseSel and=0A=
		 * ThermSenseCoreSel bits were introduced in Revision F=0A=
		 * but CurTmp seems working fine as early as Revision C.=0A=
		 * However, it is not clear whether ThermSenseSel and/or=0A=
		 * ThermSenseCoreSel work in undocumented cases as well.=0A=
		 * In fact, the Linux driver suggests it may not work but=0A=
		 * we just assume it does until we find otherwise.=0A=
		 *=0A=
		 * XXX According to Linux, CurTmp starts at -28C on=0A=
		 * Socket AM2 Revision G processors, which is not=0A=
		 * documented anywhere.=0A=
		 * XXX check TjOffset and DiodeOffset for -49C / -28C=0A=
		 */=0A=
		if ((model =3D=3D 0x04 && (cpuid & CPUID_STEPPING) =3D=3D 0) ||=0A=
		    (model =3D=3D 0x05 && (cpuid & CPUID_STEPPING) <=3D 1))=0A=
			break; /* No ThermalTrip. */=0A=
		sc->flags |=3D AMDTEMP_F_TTS;=0A=
		if (model >=3D 0x40)=0A=
			sc->tts_flags |=3D AMDTEMP_TTS_F_CS_SWAP;=0A=
		if (model >=3D 0x60 && model !=3D 0xc1) {=0A=
			do_cpuid(0x80000001, regs);=0A=
			bid =3D (regs[1] >> 9) & 0x1f;=0A=
			switch (model) {=0A=
			case 0x68: /* Socket S1g1 */=0A=
			case 0x6c:=0A=
			case 0x7c:=0A=
				break;=0A=
			case 0x6b: /* Socket AM2 and ASB1 (2 cores) */=0A=
				if (bid !=3D 0x0b &&=0A=
				    bid !=3D 0x0c)=0A=
					sc->tts_flags |=3D AMDTEMP_TTS_F_OFF28;=0A=
				break;=0A=
			case 0x6f: /* Socket AM2 and ASB1 (1 core) */=0A=
			case 0x7f:=0A=
				if (bid !=3D 0x07 &&=0A=
				    bid !=3D 0x09 &&=0A=
				    bid !=3D 0x0c)=0A=
					sc->tts_flags |=3D AMDTEMP_TTS_F_OFF28;=0A=
				break;=0A=
			default:=0A=
				sc->tts_flags |=3D AMDTEMP_TTS_F_OFF28;=0A=
			}=0A=
			sc->tts_flags |=3D AMDTEMP_TTS_F_CT_10BIT;=0A=
		}=0A=
		break;=0A=
	case 0x10:=0A=
		sc->flags |=3D AMDTEMP_F_RTC;=0A=
		reg_ctrl.u32 =3D pci_read_config(dev, AMD_REG_SBI_CTRL, 4);=0A=
		if (0 =3D=3D reg_ctrl.bits.SbTsiDis)=0A=
			sc->flags |=3D AMDTEMP_F_TSI;=0A=
		/*=0A=
		 * Erratum 319 Inaccurate Temperature Measurement=0A=
		 * http://support.amd.com/us/Processor_TechDocs/41322.pdf=0A=
		 */=0A=
		do_cpuid(0x80000001, regs);=0A=
		switch ((regs[1] >> 28) & 0xf) {=0A=
		case 0:	/* Socket F */=0A=
			erratum319 =3D 1;=0A=
			break;=0A=
		case 1:	/* Socket AM2+ or AM3 */=0A=
			if ((pci_cfgregread(pci_get_bus(dev), pci_get_slot(dev), 2,=0A=
			    AMD_REG_DRAM_CONF_HIGH, 2) & AMD_REG_DRAM_MODE_DDR3) !=3D 0 ||=0A=
			    model > 0x04 ||=0A=
			    (model =3D=3D 0x04 && (cpuid & CPUID_STEPPING) >=3D 3))=0A=
				break;=0A=
			/* XXX 00100F42h (RB-C2) exists in both formats. */=0A=
			erratum319 =3D 1;=0A=
			break;=0A=
		}=0A=
		break;=0A=
	case 0x11:=0A=
	case 0x12:=0A=
	case 0x14:=0A=
		sc->flags |=3D AMDTEMP_F_RTC;=0A=
		reg_ctrl.u32 =3D pci_read_config(dev, AMD_REG_SBI_CTRL, 4);=0A=
		if (0 =3D=3D reg_ctrl.bits.SbRmiDis) /* =3D SbTsiDis */=0A=
			sc->flags |=3D AMDTEMP_F_TSI;=0A=
		break;=0A=
	case 0x15:=0A=
	case 0x16:=0A=
	default:=0A=
		sc->flags |=3D AMDTEMP_F_RTC;=0A=
		/* XXX TODO: read TSI via SMBus. */=0A=
		break;=0A=
	}=0A=
=0A=
	if (0 !=3D (sc->flags & AMDTEMP_F_TTS)) { /* Thermaltrip Status */=0A=
		node =3D SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tts",=0A=
		    CTLFLAG_RD, NULL, "Thermaltrip Status");=0A=
		list =3D SYSCTL_CHILDREN(node);=0A=
		amdtemp_sysctl_reg_add(sc, list, amdtemp_thermtrip_status_reg_bits);=0A=
		for (i =3D 0; i < sc->cpu_ncores && i < 2; i ++) {=0A=
			snprintf(str, sizeof(str), "core%i", i);=0A=
			sub_node =3D SYSCTL_ADD_NODE(ctx, list, OID_AUTO, str,=0A=
			    CTLFLAG_RD, NULL, "CPU core sensors");=0A=
			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO,=0A=
			    "sensor0", (CTLTYPE_INT | CTLFLAG_RD), sc,=0A=
			    MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0),=0A=
			    amdtemp_tts_temp_reg_sysctl, "IK", "Sensor 0 temperature");=0A=
			SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO,=0A=
			    "sensor1", (CTLTYPE_INT | CTLFLAG_RD), sc,=0A=
			    MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 1),=0A=
			    amdtemp_tts_temp_reg_sysctl, "IK", "Sensor 1 temperature");=0A=
			SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO,=0A=
			    "sensor0_offset", CTLFLAG_RW,=0A=
			    &sc->tts_temp_offset[((i << 1) | 0)], 0,=0A=
			    "Temperature sensor offset");=0A=
			SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO,=0A=
			    "sensor1_offset", CTLFLAG_RW,=0A=
			    &sc->tts_temp_offset[((i << 1) | 1)], 0,=0A=
			    "Temperature sensor offset");=0A=
		}=0A=
	}=0A=
	if (0 !=3D (sc->flags & AMDTEMP_F_RTC)) { /* Reported Temperature =
Control */=0A=
		node =3D SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "rtc",=0A=
		    CTLFLAG_RD, NULL, "Reported Temperature Control");=0A=
		list =3D SYSCTL_CHILDREN(node);=0A=
		amdtemp_sysctl_reg_add(sc, list, amdtemp_reptmp_reg_bits);=0A=
		SYSCTL_ADD_INT(ctx, list, OID_AUTO, "sensor_offset", CTLFLAG_RW,=0A=
		    &sc->rtc_temp_offset, 0, "Temperature sensor offset");=0A=
	}=0A=
	if (0 !=3D (sc->flags & AMDTEMP_F_TSI)) { /* Temperature Sensor =
Interface */=0A=
		node =3D SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "tsi",=0A=
		    CTLFLAG_RD, NULL, "Temperature Sensor Interface");=0A=
		list =3D SYSCTL_CHILDREN(node);=0A=
		for (i =3D 0; i < 8; i ++) {=0A=
			if (0 =3D=3D amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION))=0A=
				continue;=0A=
			snprintf(str, sizeof(str), "sensor%i", i);=0A=
			sub_node =3D SYSCTL_ADD_NODE(ctx, list, OID_AUTO, str,=0A=
			    CTLFLAG_RD, NULL, "TSI sensor");=0A=
			amdtemp_sysctl_reg_add2(sc, SYSCTL_CHILDREN(sub_node),=0A=
			    amdtemp_tsi_regs, i);=0A=
			SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(sub_node), OID_AUTO,=0A=
			    "sensor_offset", CTLFLAG_RW, &sc->tsi_temp_offset[i], 0,=0A=
			    "Temperature sensor offset");=0A=
		}=0A=
	}=0A=
	=0A=
	if (bootverbose) {=0A=
		if (0 !=3D (sc->flags & AMDTEMP_F_TTS))=0A=
			device_printf(dev, "Found: Thermaltrip Status.\n");=0A=
		if (0 !=3D (sc->flags & AMDTEMP_F_RTC))=0A=
			device_printf(dev, "Found: Reported Temperature Control.\n");=0A=
		if (0 !=3D (sc->flags & AMDTEMP_F_TSI))=0A=
			device_printf(dev, "Found: Temperature Sensor Interface via CPU =
registers.\n");=0A=
	}=0A=
	if (erratum319)=0A=
		device_printf(dev,=0A=
		    "Erratum 319: temperature measurement may be inaccurate\n");=0A=
	/*=0A=
	 * Try to create dev.cpu sysctl entries and setup intrhook function.=0A=
	 * This is needed because the cpu driver may be loaded late on boot,=0A=
	 * after us.=0A=
	 */=0A=
	amdtemp_intrhook(dev);=0A=
	if (NULL =3D=3D sc->sysctl_cpu[i]) {=0A=
		sc->sc_ich.ich_func =3D amdtemp_intrhook;=0A=
		sc->sc_ich.ich_arg =3D sc;=0A=
		if (config_intrhook_establish(&sc->sc_ich) !=3D 0) {=0A=
			amdtemp_detach(dev);=0A=
			device_printf(dev, "config_intrhook_establish failed!\n");=0A=
			return (ENXIO);=0A=
		}=0A=
	}=0A=
	return (0);=0A=
}=0A=
=0A=
int=0A=
amdtemp_detach(device_t dev) {=0A=
	struct amdtemp_softc *sc =3D device_get_softc(dev);=0A=
	uint32_t i;=0A=
=0A=
	for (i =3D 0; i < sc->cpu_ncores; i++)=0A=
		if (sc->sysctl_cpu[i] !=3D NULL)=0A=
			sysctl_remove_oid(sc->sysctl_cpu[i], 1, 0);=0A=
	/* NewBus removes the dev.amdtemp.N tree by itself. */=0A=
	if (sc->sc_ich.ich_arg !=3D NULL) {=0A=
		sc->sc_ich.ich_arg =3D NULL;=0A=
		config_intrhook_disestablish(&sc->sc_ich);=0A=
	}=0A=
	mtx_destroy(&sc->lock);=0A=
=0A=
	return (0);=0A=
}=0A=
=0A=
void=0A=
amdtemp_intrhook(void *arg) {=0A=
	struct amdtemp_softc *sc =3D arg;=0A=
	struct sysctl_ctx_list *sysctlctx;=0A=
	device_t dev =3D sc->dev, acpi, cpu, nexus;=0A=
	int (*sysctl_handler)(SYSCTL_HANDLER_ARGS);=0A=
	intptr_t sysctl_arg2;=0A=
	uint32_t i, unit_base;=0A=
=0A=
	if (sc->sc_ich.ich_arg !=3D NULL) {=0A=
		sc->sc_ich.ich_arg =3D NULL;=0A=
		config_intrhook_disestablish(&sc->sc_ich);=0A=
	}=0A=
=0A=
	/* dev.cpu.N.temperature. */=0A=
	nexus =3D device_find_child(root_bus, "nexus", 0);=0A=
	acpi =3D device_find_child(nexus, "acpi", 0);=0A=
	unit_base =3D (device_get_unit(dev) * sc->cpu_ncores); /* XXX: =
cpu_ncores not constant for different CPUs... */=0A=
=0A=
	for (i =3D 0; i < sc->cpu_ncores; i ++) {=0A=
		if (sc->sysctl_cpu[i] !=3D NULL)=0A=
			continue;=0A=
		cpu =3D device_find_child(acpi, "cpu", (unit_base + i));=0A=
		if (cpu =3D=3D NULL)=0A=
			continue;=0A=
		sysctl_handler =3D NULL;=0A=
		if (0 !=3D (sc->flags & AMDTEMP_F_TSI)) { /* Temperature Sensor =
Interface */=0A=
			if (0 =3D=3D amdtemp_sbi_read(sc, i, SB_TSI_REG_REVISION))=0A=
				continue;=0A=
			sysctl_handler =3D amdtemp_tsi_temp_reg_sysctl;=0A=
			sysctl_arg2 =3D MAKE_ARG2(SB_TSI_REG_CPU_TEMP_LB,=0A=
			    SB_TSI_REG_CPU_TEMP_HB, i);=0A=
		} else if (0 !=3D (sc->flags & AMDTEMP_F_RTC)) { /* Reported =
Temperature Control */=0A=
			sysctl_handler =3D amdtemp_rtc_temp_sysctl;=0A=
			sysctl_arg2 =3D MAKE_ARG2(AMD_REG_REPTMP_CTRL, 21, 11);=0A=
		} else if (0 !=3D (sc->flags & AMDTEMP_F_TTS)) { /* Thermaltrip Status =
*/=0A=
			sysctl_handler =3D amdtemp_tts_temp_reg_sysctl;=0A=
			sysctl_arg2 =3D MAKE_ARG2(AMD_REG_THERMTRIP_STAT, i, 0xff);=0A=
		}=0A=
		if (NULL =3D=3D sysctl_handler)=0A=
			continue;=0A=
		sysctlctx =3D device_get_sysctl_ctx(cpu);=0A=
		sc->sysctl_cpu[i] =3D SYSCTL_ADD_PROC(sysctlctx,=0A=
		    SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), OID_AUTO,=0A=
		    "temperature", (CTLTYPE_INT | CTLFLAG_RD), sc, sysctl_arg2,=0A=
		    sysctl_handler, "IK", "Current temparature");=0A=
	}=0A=
}=0A=
=0A=
=0A=
/* Sysctl staff. */=0A=
static void=0A=
amdtemp_sysctl_reg_add(struct amdtemp_softc *sc, struct sysctl_oid_list =
*child,=0A=
    struct amdtemp_sysctl_reg *regs) {=0A=
	struct sysctl_ctx_list *ctx =3D device_get_sysctl_ctx(sc->dev);=0A=
	uint32_t i;=0A=
=0A=
	for (i =3D 0; NULL !=3D regs[i].oid_handler; i ++) {=0A=
		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, regs[i].name,=0A=
		    regs[i].flags, sc,=0A=
		    MAKE_ARG2(regs[i].reg, regs[i].a1, regs[i].a2),=0A=
		    regs[i].oid_handler, regs[i].fmt, regs[i].descr);=0A=
	}=0A=
}=0A=
=0A=
static void=0A=
amdtemp_sysctl_reg_add2(struct amdtemp_softc *sc, struct sysctl_oid_list =
*child,=0A=
    struct amdtemp_sysctl_reg *regs, uint32_t a2) {=0A=
	struct sysctl_ctx_list *ctx =3D device_get_sysctl_ctx(sc->dev);=0A=
	uint32_t i;=0A=
=0A=
	for (i =3D 0; NULL !=3D regs[i].oid_handler; i ++) {=0A=
		SYSCTL_ADD_PROC(ctx, child, OID_AUTO, regs[i].name,=0A=
		    regs[i].flags, sc,=0A=
		    MAKE_ARG2(regs[i].reg, regs[i].a1, a2),=0A=
		    regs[i].oid_handler, regs[i].fmt, regs[i].descr);=0A=
	}=0A=
}=0A=
=0A=
static int=0A=
amdtemp_sysctl_reg_bits(SYSCTL_HANDLER_ARGS) {=0A=
	struct amdtemp_softc *sc =3D arg1;=0A=
	uint32_t i, reg_data, reg_num, bits_off, bits_len, bits_mask =3D 0;=0A=
	unsigned val;=0A=
	int error;=0A=
=0A=
	reg_num =3D ARG2_GET_REG(arg2);=0A=
	bits_off =3D ARG2_GET_A1(arg2);=0A=
	bits_len =3D ARG2_GET_A2(arg2);=0A=
	reg_data =3D pci_read_config(sc->dev, reg_num, 4);=0A=
=0A=
	for(i =3D 0; i < bits_len; i ++)=0A=
		bits_mask |=3D ((uint32_t)1 << i);=0A=
=0A=
	val =3D ((reg_data >> bits_off) & bits_mask);=0A=
	error =3D sysctl_handle_int(oidp, &val, 0, req);=0A=
	if (0 !=3D error || NULL =3D=3D req->newptr || val =3D=3D reg_data)=0A=
		return (error);=0A=
	reg_data &=3D ~(bits_mask << bits_off); // clear all bits at offset=0A=
	reg_data |=3D ((val & bits_mask) << bits_off); // set value bits=0A=
	pci_write_config(sc->dev, reg_num, reg_data, 4);=0A=
=0A=
	return (0);=0A=
}=0A=
=0A=
=0A=
/* Thermaltrip Status Register */=0A=
static uint32_t=0A=
amdtemp_tts_get_temp(struct amdtemp_softc *sc, uint32_t reg, uint8_t =
core,=0A=
    uint8_t sense) {=0A=
	union reg_amd_thermtrip_status_desc reg_tts;=0A=
	uint32_t val;=0A=
=0A=
	reg_tts.u32 =3D 0;=0A=
	if (0 =3D=3D (sc->tts_flags & AMDTEMP_TTS_F_CS_SWAP))=0A=
		reg_tts.bits.ThermSenseCoreSel =3D ((0 !=3D core) ? 1 : 0);=0A=
	else /* Swap. */=0A=
		reg_tts.bits.ThermSenseCoreSel =3D ((0 !=3D core) ? 0 : 1);=0A=
	reg_tts.bits.ThermSenseSel =3D ((0 !=3D sense) ? 1 : 0);=0A=
=0A=
	AMDTEMP_LOCK(sc);=0A=
	pci_write_config(sc->dev, reg, reg_tts.u32, 4);=0A=
	reg_tts.u32 =3D pci_read_config(sc->dev, reg, 4);=0A=
	AMDTEMP_UNLOCK(sc);=0A=
=0A=
	val =3D reg_tts.bits.CurTmp;=0A=
	if (0 =3D=3D (sc->tts_flags & AMDTEMP_TTS_F_CT_10BIT))=0A=
		val &=3D ~3; /* Clear first 2 bits. */=0A=
	val =3D (AMDTEMP_ZERO_C_TO_K + ((val * 5) / 2) -=0A=
	    ((0 !=3D (sc->tts_flags & AMDTEMP_TTS_F_OFF28)) ? 280 : 490));=0A=
	val +=3D (sc->tts_temp_offset[((reg_tts.bits.ThermSenseCoreSel << 1) |=0A=
	    reg_tts.bits.ThermSenseSel)] * 10);=0A=
=0A=
	return (val);=0A=
}=0A=
/* If 0xff =3D=3D ARG2_GET_A2(arg2) then retun max temp for core. */=0A=
static int=0A=
amdtemp_tts_temp_reg_sysctl(SYSCTL_HANDLER_ARGS) {=0A=
	struct amdtemp_softc *sc =3D arg1;=0A=
	uint32_t reg_num;=0A=
	unsigned val;=0A=
	int error;=0A=
=0A=
	reg_num =3D ARG2_GET_REG(arg2);=0A=
	if (0xff =3D=3D ARG2_GET_A2(arg2)) {=0A=
		val =3D imax(amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 0),=0A=
		    amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2), 1));=0A=
	} else {=0A=
		val =3D amdtemp_tts_get_temp(sc, reg_num, ARG2_GET_A1(arg2),=0A=
		    ARG2_GET_A2(arg2));=0A=
	}=0A=
	error =3D sysctl_handle_int(oidp, &val, 0, req);=0A=
	if (0 !=3D error || NULL =3D=3D req->newptr)=0A=
		return (error);=0A=
	return (0);=0A=
}=0A=
=0A=
=0A=
/* D18F3xA4 Reported Temperature Control Register */=0A=
static int=0A=
amdtemp_rtc_temp_sysctl(SYSCTL_HANDLER_ARGS) {=0A=
	struct amdtemp_softc *sc =3D arg1;=0A=
	union reg_amd_rep_tmp_ctrl_desc reg_ctrl;=0A=
	uint32_t reg_num, bits_off;=0A=
	unsigned val;=0A=
	int error;=0A=
=0A=
	reg_num =3D ARG2_GET_REG(arg2);=0A=
	bits_off =3D ARG2_GET_A1(arg2);=0A=
=0A=
	AMDTEMP_LOCK(sc);=0A=
	reg_ctrl.u32 =3D pci_read_config(sc->dev, reg_num, 4);=0A=
	switch (bits_off) {=0A=
	case 16: /* CurTmpTjSel */=0A=
		reg_ctrl.bits.CurTmpTjSel =3D 3;=0A=
		break;=0A=
	case 21: /* CurTmp */=0A=
		reg_ctrl.bits.CurTmpTjSel =3D 0;=0A=
		break;=0A=
	}=0A=
	pci_write_config(sc->dev, reg_num, reg_ctrl.u32, 4);=0A=
	reg_ctrl.u32 =3D pci_read_config(sc->dev, reg_num, 4);=0A=
	if (bits_off =3D=3D 16) { /* CurTmpTjSel: switch back to CurTmp. */=0A=
		reg_ctrl.bits.CurTmpTjSel =3D 0;=0A=
		pci_write_config(sc->dev, reg_num, reg_ctrl.u32, 4);=0A=
	}=0A=
	AMDTEMP_UNLOCK(sc);=0A=
=0A=
	val =3D (AMDTEMP_ZERO_C_TO_K + ((reg_ctrl.bits.CurTmp * 5) / 4));=0A=
	if (16 =3D=3D bits_off) /* CurTmpTjSel */=0A=
		val -=3D 490;=0A=
	else=0A=
		val +=3D (sc->rtc_temp_offset * 10);=0A=
	error =3D sysctl_handle_int(oidp, &val, 0, req);=0A=
	if (0 !=3D error || NULL =3D=3D req->newptr)=0A=
		return (error);=0A=
	//device_printf(sc->dev, "amdtemp_rtc_temp_sysctl: reg_num =3D %i, =
bits_off =3D %i, val =3D %i, reg_ctrl.u32 =3D %i\n", reg_num, bits_off, =
val, reg_ctrl.u32);=0A=
	//pci_write_config(sc->dev, reg_num, reg_ctrl.u32, 4);=0A=
	return (0);=0A=
}=0A=
=0A=
=0A=
/* Set SMBus-based sideband interface address: 0-7. */=0A=
static void=0A=
amdtemp_sbi_set_addr(struct amdtemp_softc *sc, uint32_t sbi_addr) {=0A=
	union reg_amd_sbi_ctrl_desc reg_ctrl;=0A=
=0A=
	sbi_addr &=3D AMD_REG_SBI_ADDR_MASK;=0A=
	reg_ctrl.u32 =3D pci_read_config(sc->dev, AMD_REG_SBI_CTRL, 4);=0A=
	if (reg_ctrl.bits.SbiAddr =3D=3D sbi_addr) /* Is address allready set? =
*/=0A=
		return;=0A=
	reg_ctrl.bits.SbiAddr =3D sbi_addr;=0A=
	pci_write_config(sc->dev, AMD_REG_SBI_CTRL, reg_ctrl.u32, 4);=0A=
}=0A=
=0A=
static uint32_t=0A=
amdtemp_sbi_read(struct amdtemp_softc *sc, uint32_t sbi_addr, uint32_t =
reg_addr) {=0A=
	uint32_t ret;=0A=
=0A=
	AMDTEMP_LOCK(sc);=0A=
	amdtemp_sbi_set_addr(sc, sbi_addr);=0A=
	pci_write_config(sc->dev, AMD_REG_SBI_ADDR, reg_addr, 4);=0A=
	ret =3D pci_read_config(sc->dev, AMD_REG_SBI_DATA, 4);=0A=
	AMDTEMP_UNLOCK(sc);=0A=
=0A=
	return (ret);=0A=
}=0A=
=0A=
static int=0A=
amdtemp_sbi_write(struct amdtemp_softc *sc, uint32_t sbi_addr, uint32_t =
reg_addr,=0A=
    uint8_t data) {=0A=
	union reg_amd_sbi_ctrl_desc reg_ctrl;=0A=
	uint32_t data32 =3D data;=0A=
=0A=
	AMDTEMP_LOCK(sc);=0A=
	amdtemp_sbi_set_addr(sc, sbi_addr);=0A=
	pci_write_config(sc->dev, AMD_REG_SBI_ADDR, reg_addr, 4);=0A=
	pci_write_config(sc->dev, AMD_REG_SBI_DATA, data32, 4);=0A=
	/* Wait write. */=0A=
	data32 =3D AMD_SBI_WRITE_TIMEOUT;=0A=
	while (data32 --) {=0A=
		reg_ctrl.u32 =3D pci_read_config(sc->dev, AMD_REG_SBI_CTRL, 4);=0A=
		if (0 !=3D reg_ctrl.bits.SbiRegWrDn)=0A=
			break;=0A=
		DELAY(100);=0A=
	}=0A=
	AMDTEMP_UNLOCK(sc);=0A=
=0A=
	if (data32 =3D=3D 0) {=0A=
		device_printf(sc->dev, "timeout waiting for SBI write.\n");=0A=
		return (1);=0A=
	}=0A=
	return (0);=0A=
}=0A=
=0A=
static int=0A=
amdtemp_tsi_reg_sysctl(SYSCTL_HANDLER_ARGS) {=0A=
	struct amdtemp_softc *sc =3D arg1;=0A=
	uint32_t reg_data, reg_addr, sbi_addr;=0A=
	unsigned val;=0A=
	int error;=0A=
=0A=
	reg_addr =3D ARG2_GET_REG(arg2);=0A=
	sbi_addr =3D (ARG2_GET_A2(arg2) & AMD_REG_SBI_ADDR_MASK);=0A=
	reg_data =3D amdtemp_sbi_read(sc, sbi_addr, reg_addr);=0A=
	val =3D reg_data;=0A=
=0A=
	error =3D sysctl_handle_int(oidp, &val, 0, req);=0A=
	if (0 !=3D error || NULL =3D=3D req->newptr || val =3D=3D reg_data)=0A=
		return (error);=0A=
	return (amdtemp_sbi_write(sc, sbi_addr, reg_addr, val));=0A=
}=0A=
=0A=
static int=0A=
amdtemp_tsi_temp_reg_sysctl(SYSCTL_HANDLER_ARGS) {=0A=
	struct amdtemp_softc *sc =3D arg1;=0A=
	uint32_t reg_data_lo, reg_data_hi, sbi_addr;=0A=
	unsigned val;=0A=
	int error;=0A=
=0A=
	sbi_addr =3D (ARG2_GET_A2(arg2) & AMD_REG_SBI_ADDR_MASK);=0A=
	reg_data_lo =3D amdtemp_sbi_read(sc, sbi_addr, ARG2_GET_REG(arg2));=0A=
	reg_data_hi =3D amdtemp_sbi_read(sc, sbi_addr, ARG2_GET_A1(arg2));=0A=
	val =3D (AMDTEMP_ZERO_C_TO_K + (reg_data_hi * 10));=0A=
	if (SB_TSI_REG_CPU_TEMP_LB =3D=3D ARG2_GET_REG(arg2)) /* Apply offset =
only to sensor. */=0A=
		val +=3D (sc->tsi_temp_offset[sbi_addr] * 10);=0A=
	if (reg_data_lo & 0x80)=0A=
		val +=3D 5; /* 0,5 C */=0A=
	if (reg_data_lo & 0x40)=0A=
		val +=3D 3; /* 0,25 C */=0A=
	if (reg_data_lo & 0x20)=0A=
		val +=3D 1; /* 0,125 C */=0A=
=0A=
	error =3D sysctl_handle_int(oidp, &val, 0, req);=0A=
	if (0 !=3D error || NULL =3D=3D req->newptr)=0A=
		return (error);=0A=
	return (0);=0A=
}=0A=

------=_NextPart_000_0206_01CEC31D.875A19E0--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?52520d5f.c402cd0a.5f4e.ffffffa2>