summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2011-05-29 00:59:38 +0000
committerattilio <attilio@FreeBSD.org>2011-05-29 00:59:38 +0000
commit55a3bf38a5f8f3d517542f92fc9e34a1cebcce52 (patch)
tree19a91bf94ba6b6dca19c88849791de347e024692 /sys/powerpc
parenteefddaeed6c0577102de6360a326fa15c36afd07 (diff)
parent16f4172df58aff2531075ad9428e980aba6a25bd (diff)
downloadFreeBSD-src-55a3bf38a5f8f3d517542f92fc9e34a1cebcce52.zip
FreeBSD-src-55a3bf38a5f8f3d517542f92fc9e34a1cebcce52.tar.gz
MFC
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/booke/locore.S68
-rw-r--r--sys/powerpc/booke/machdep.c53
-rw-r--r--sys/powerpc/booke/platform_bare.c51
-rw-r--r--sys/powerpc/booke/pmap.c25
-rw-r--r--sys/powerpc/include/param.h2
-rw-r--r--sys/powerpc/include/spr.h4
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx.c21
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx.h5
-rw-r--r--sys/powerpc/powermac/powermac_thermal.c176
-rw-r--r--sys/powerpc/powermac/powermac_thermal.h54
-rw-r--r--sys/powerpc/powermac/smu.c199
-rw-r--r--sys/powerpc/powermac/smusat.c50
12 files changed, 447 insertions, 261 deletions
diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S
index 3ac4a1a..de7effc 100644
--- a/sys/powerpc/booke/locore.S
+++ b/sys/powerpc/booke/locore.S
@@ -83,17 +83,18 @@ __start:
* locore registers use:
* r1 : stack pointer
* r2 : trace pointer (AP only, for early diagnostics)
- * r3-r27 : scratch registers
- * r28 : kernload
- * r29 : temp TLB1 entry
- * r30 : initial TLB1 entry we started in
- * r31 : metadata pointer
+ * r3-r26 : scratch registers
+ * r27 : kernload
+ * r28 : temp TLB1 entry
+ * r29 : initial TLB1 entry we started in
+ * r30-r31 : arguments (metadata pointer)
*/
/*
- * Keep metadata ptr in r31 for later use.
+ * Keep arguments in r30 & r31 for later use.
*/
- mr %r31, %r3
+ mr %r30, %r3
+ mr %r31, %r4
/*
* Initial cleanup
@@ -120,7 +121,7 @@ __start:
*/
bl 1f
1: mflr %r3
- bl tlb1_find_current /* the entry number found is returned in r30 */
+ bl tlb1_find_current /* the entry found is returned in r29 */
bl tlb1_inval_all_but_current
/*
@@ -140,7 +141,7 @@ __start:
/*
* Invalidate initial entry
*/
- mr %r3, %r30
+ mr %r3, %r29
bl tlb1_inval_entry
/*
@@ -148,7 +149,7 @@ __start:
*/
/* Final kernel mapping, map in 16 MB of RAM */
lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */
- li %r4, 1 /* Entry 1 */
+ li %r4, 0 /* Entry 0 */
rlwimi %r3, %r4, 16, 12, 15
mtspr SPR_MAS0, %r3
isync
@@ -170,7 +171,7 @@ __start:
bl 3f
3: mflr %r4 /* Use current address */
rlwinm %r4, %r4, 0, 0, 7 /* 16MB alignment mask */
- mr %r28, %r4 /* Keep kernel load address */
+ mr %r27, %r4 /* Keep kernel load address */
ori %r4, %r4, (MAS3_SX | MAS3_SW | MAS3_SR)@l
mtspr SPR_MAS3, %r4 /* Set RPN and protection */
isync
@@ -193,7 +194,7 @@ __start:
/*
* Invalidate temp mapping
*/
- mr %r3, %r29
+ mr %r3, %r28
bl tlb1_inval_entry
/*
@@ -201,7 +202,7 @@ __start:
*/
lis %r3, kernload@ha
addi %r3, %r3, kernload@l
- stw %r28, 0(%r3)
+ stw %r27, 0(%r3)
#ifdef SMP
/*
* APs need a separate copy of kernload info within the __boot_page
@@ -210,7 +211,7 @@ __start:
*/
lis %r3, kernload_ap@ha
addi %r3, %r3, kernload_ap@l
- stw %r28, 0(%r3)
+ stw %r27, 0(%r3)
msync
#endif
@@ -229,14 +230,11 @@ __start:
/*
* Set up arguments and jump to system initialization code
*/
- lis %r3, kernel_text@ha
- addi %r3, %r3, kernel_text@l
- lis %r4, _end@ha
- addi %r4, %r4, _end@l
- mr %r5, %r31 /* metadata ptr */
+ mr %r3, %r30
+ mr %r4, %r31
/* Prepare e500 core */
- bl e500_init
+ bl booke_init
/* Switch to thread0.td_kstack now */
mr %r1, %r3
@@ -290,7 +288,7 @@ kernload_ap:
*/
bl 2f
2: mflr %r3
- bl tlb1_find_current /* the entry number found is in r30 */
+ bl tlb1_find_current /* the entry number found is in r29 */
bl tlb1_inval_all_but_current
/*
@@ -310,7 +308,7 @@ kernload_ap:
/*
* Invalidate initial entry
*/
- mr %r3, %r30
+ mr %r3, %r29
bl tlb1_inval_entry
/*
@@ -318,7 +316,7 @@ kernload_ap:
*/
/* Final kernel mapping, map in 16 MB of RAM */
lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */
- li %r4, 1 /* Entry 1 */
+ li %r4, 0 /* Entry 0 */
rlwimi %r3, %r4, 16, 4, 15
mtspr SPR_MAS0, %r3
isync
@@ -373,7 +371,7 @@ kernload_ap:
/*
* Invalidate temp mapping
*/
- mr %r3, %r29
+ mr %r3, %r28
bl tlb1_inval_entry
/*
@@ -425,7 +423,7 @@ tlb_inval_all:
blr
/*
- * expects address to look up in r3, returns entry number in r30
+ * expects address to look up in r3, returns entry number in r29
*
* FIXME: the hidden assumption is we are now running in AS=0, but we should
* retrieve actual AS from MSR[IS|DS] and put it in MAS6[SAS]
@@ -437,7 +435,7 @@ tlb1_find_current:
isync
tlbsx 0, %r3
mfspr %r17, SPR_MAS0
- rlwinm %r30, %r17, 16, 20, 31 /* MAS0[ESEL] -> r30 */
+ rlwinm %r29, %r17, 16, 20, 31 /* MAS0[ESEL] -> r29 */
/* Make sure we have IPROT set on the entry */
mfspr %r17, SPR_MAS1
@@ -470,14 +468,14 @@ tlb1_inval_entry:
blr
/*
- * r30 current entry number
- * r29 returned temp entry
+ * r29 current entry number
+ * r28 returned temp entry
* r3-r5 scratched
*/
tlb1_temp_mapping_as1:
/* Read our current translation */
lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */
- rlwimi %r3, %r30, 16, 12, 15 /* Select our current entry */
+ rlwimi %r3, %r29, 16, 12, 15 /* Select our current entry */
mtspr SPR_MAS0, %r3
isync
tlbre
@@ -489,12 +487,8 @@ tlb1_temp_mapping_as1:
* entry is the last in TLB1
*/
lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */
- addi %r29, %r30, 1 /* Use next entry. */
- li %r4, 1
- cmpw %r4, %r29
- bne 1f
- addi %r29, %r29, 1
-1: rlwimi %r3, %r29, 16, 12, 15 /* Select temp entry */
+ addi %r28, %r29, 1 /* Use next entry. */
+ rlwimi %r3, %r28, 16, 12, 15 /* Select temp entry */
mtspr SPR_MAS0, %r3
isync
mfspr %r5, SPR_MAS1
@@ -514,7 +508,7 @@ tlb1_temp_mapping_as1:
* Loops over TLB1, invalidates all entries skipping the one which currently
* maps this code.
*
- * r30 current entry
+ * r29 current entry
* r3-r5 scratched
*/
tlb1_inval_all_but_current:
@@ -528,7 +522,7 @@ tlb1_inval_all_but_current:
isync
tlbre
mfspr %r5, SPR_MAS1
- cmpw %r4, %r30 /* our current entry? */
+ cmpw %r4, %r29 /* our current entry? */
beq 2f
rlwinm %r5, %r5, 0, 2, 31 /* clear VALID and IPROT bits */
mtspr SPR_MAS1, %r5
diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c
index f2dbacf..c2b5e6f 100644
--- a/sys/powerpc/booke/machdep.c
+++ b/sys/powerpc/booke/machdep.c
@@ -190,7 +190,7 @@ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_e500_startup, NULL);
void print_kernel_section_addr(void);
void print_kenv(void);
-u_int e500_init(u_int32_t, u_int32_t, void *);
+u_int booke_init(uint32_t, uint32_t);
static void
cpu_e500_startup(void *dummy)
@@ -276,19 +276,41 @@ print_kernel_section_addr(void)
}
u_int
-e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
+booke_init(uint32_t arg1, uint32_t arg2)
{
struct pcpu *pc;
- void *kmdp;
+ void *kmdp, *mdp;
vm_offset_t dtbp, end;
uint32_t csr;
kmdp = NULL;
- end = endkernel;
+ end = (uintptr_t)_end;
dtbp = (vm_offset_t)NULL;
/*
+ * Handle the various ways we can get loaded and started:
+ * - FreeBSD's loader passes the pointer to the metadata
+ * in arg1, with arg2 undefined. arg1 has a value that's
+ * relative to the kernel's link address (i.e. larger
+ * than 0xc0000000).
+ * - Juniper's loader passes the metadata pointer in arg2
+ * and sets arg1 to zero. This is to signal that the
+ * loader maps the kernel and starts it at its link
+ * address (unlike the FreeBSD loader).
+ * - U-Boot passes the standard argc and argv parameters
+ * in arg1 and arg2 (resp). arg1 is between 1 and some
+ * relatively small number, such as 64K. arg2 is the
+ * physical address of the argv vector.
+ */
+ if (arg1 > (uintptr_t)kernel_text) /* FreeBSD loader */
+ mdp = (void *)arg1;
+ else if (arg1 == 0) /* Juniper loader */
+ mdp = (void *)arg2;
+ else /* U-Boot */
+ mdp = NULL;
+
+ /*
* Parse metadata and fetch parameters.
*/
if (mdp != NULL) {
@@ -309,17 +331,8 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
#endif
}
} else {
- /*
- * We should scream but how? Cannot even output anything...
- */
-
- /*
- * FIXME add return value and handle in the locore so we can
- * return to the loader maybe? (this seems not very easy to
- * restore everything as the TLB have all been reprogrammed
- * in the locore etc...)
- */
- while (1);
+ bzero(__sbss_start, __sbss_end - __sbss_start);
+ bzero(__bss_start, _end - __bss_start);
}
#if defined(FDT_DTB_STATIC)
@@ -368,9 +381,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
cninit();
/* Print out some debug info... */
- debugf("e500_init: console initialized\n");
- debugf(" arg1 startkernel = 0x%08x\n", startkernel);
- debugf(" arg2 endkernel = 0x%08x\n", endkernel);
+ debugf("%s: console initialized\n", __func__);
debugf(" arg3 mdp = 0x%08x\n", (u_int32_t)mdp);
debugf(" end = 0x%08x\n", (u_int32_t)end);
debugf(" boothowto = 0x%08x\n", boothowto);
@@ -403,7 +414,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
/* Initialise virtual memory. */
pmap_mmu_install(MMU_TYPE_BOOKE, 0);
- pmap_bootstrap(startkernel, end);
+ pmap_bootstrap((uintptr_t)kernel_text, end);
debugf("MSR = 0x%08x\n", mfmsr());
//tlb1_print_entries();
//tlb1_print_tlbentries();
@@ -449,8 +460,8 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp)
printf("L1 I-cache %sabled\n",
(csr & L1CSR1_ICE) ? "en" : "dis");
- debugf("e500_init: SP = 0x%08x\n", ((uintptr_t)thread0.td_pcb - 16) & ~15);
- debugf("e500_init: e\n");
+ debugf("%s: SP = 0x%08x\n", __func__,
+ ((uintptr_t)thread0.td_pcb - 16) & ~15);
return (((uintptr_t)thread0.td_pcb - 16) & ~15);
}
diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c
index 0fbb98a..d76664e 100644
--- a/sys/powerpc/booke/platform_bare.c
+++ b/sys/powerpc/booke/platform_bare.c
@@ -104,10 +104,22 @@ bare_probe(platform_t plat)
int i, law_max, tgt;
ver = SVR_VER(mfspr(SPR_SVR));
- if (ver == SVR_MPC8572E || ver == SVR_MPC8572)
+ switch (ver & ~0x0008) { /* Mask Security Enabled bit */
+ case SVR_P4080:
+ maxcpu = 8;
+ break;
+ case SVR_P4040:
+ maxcpu = 4;
+ break;
+ case SVR_MPC8572:
+ case SVR_P1020:
+ case SVR_P2020:
maxcpu = 2;
- else
+ break;
+ default:
maxcpu = 1;
+ break;
+ }
/*
* Clear local access windows. Skip DRAM entries, so we don't shoot
@@ -280,24 +292,23 @@ bare_smp_start_cpu(platform_t plat, struct pcpu *pc)
static void
e500_reset(platform_t plat)
{
- uint32_t ver = SVR_VER(mfspr(SPR_SVR));
-
- if (ver == SVR_MPC8572E || ver == SVR_MPC8572 ||
- ver == SVR_MPC8548E || ver == SVR_MPC8548)
- /* Systems with dedicated reset register */
- ccsr_write4(OCP85XX_RSTCR, 2);
- else {
- /* Clear DBCR0, disables debug interrupts and events. */
- mtspr(SPR_DBCR0, 0);
- __asm __volatile("isync");
-
- /* Enable Debug Interrupts in MSR. */
- mtmsr(mfmsr() | PSL_DE);
-
- /* Enable debug interrupts and issue reset. */
- mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM |
- DBCR0_RST_SYSTEM);
- }
+
+ /*
+ * Try the dedicated reset register first.
+ * If the SoC doesn't have one, we'll fall
+ * back to using the debug control register.
+ */
+ ccsr_write4(OCP85XX_RSTCR, 2);
+
+ /* Clear DBCR0, disables debug interrupts and events. */
+ mtspr(SPR_DBCR0, 0);
+ __asm __volatile("isync");
+
+ /* Enable Debug Interrupts in MSR. */
+ mtmsr(mfmsr() | PSL_DE);
+
+ /* Enable debug interrupts and issue reset. */
+ mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM);
printf("Reset failed...\n");
while (1);
diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c
index 11be68e..81fce09 100644
--- a/sys/powerpc/booke/pmap.c
+++ b/sys/powerpc/booke/pmap.c
@@ -92,9 +92,6 @@ __FBSDID("$FreeBSD$");
#include "mmu_if.h"
-#define DEBUG
-#undef DEBUG
-
#ifdef DEBUG
#define debugf(fmt, args...) printf(fmt, ##args)
#else
@@ -947,7 +944,7 @@ pte_find(mmu_t mmu, pmap_t pmap, vm_offset_t va)
/**************************************************************************/
/*
- * This is called during e500_init, before the system is really initialized.
+ * This is called during booke_init, before the system is really initialized.
*/
static void
mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend)
@@ -3022,24 +3019,18 @@ tlb1_init(vm_offset_t ccsrbar)
{
uint32_t mas0;
- /* TLB1[1] is used to map the kernel. Save that entry. */
- mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(1);
+ /* TLB1[0] is used to map the kernel. Save that entry. */
+ mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(0);
mtspr(SPR_MAS0, mas0);
__asm __volatile("isync; tlbre");
- tlb1[1].mas1 = mfspr(SPR_MAS1);
- tlb1[1].mas2 = mfspr(SPR_MAS2);
- tlb1[1].mas3 = mfspr(SPR_MAS3);
+ tlb1[0].mas1 = mfspr(SPR_MAS1);
+ tlb1[0].mas2 = mfspr(SPR_MAS2);
+ tlb1[0].mas3 = mfspr(SPR_MAS3);
- /* Map in CCSRBAR in TLB1[0] */
- tlb1_idx = 0;
+ /* Map in CCSRBAR in TLB1[1] */
+ tlb1_idx = 1;
tlb1_set_entry(CCSRBAR_VA, ccsrbar, CCSRBAR_SIZE, _TLB_ENTRY_IO);
- /*
- * Set the next available TLB1 entry index. Note TLB[1] is reserved
- * for initial mapping of kernel text+data, which was set early in
- * locore, we need to skip this [busy] entry.
- */
- tlb1_idx = 2;
/* Setup TLB miss defaults */
set_mas4_defaults();
diff --git a/sys/powerpc/include/param.h b/sys/powerpc/include/param.h
index d71d048..06b131c 100644
--- a/sys/powerpc/include/param.h
+++ b/sys/powerpc/include/param.h
@@ -68,7 +68,7 @@
#endif
#if defined(SMP) || defined(KLD_MODULE)
-#define MAXCPU 4
+#define MAXCPU 8
#else
#define MAXCPU 1
#endif /* SMP || KLD_MODULE */
diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h
index f08f614..4f675c3 100644
--- a/sys/powerpc/include/spr.h
+++ b/sys/powerpc/include/spr.h
@@ -662,6 +662,10 @@
#define SVR_P2010E 0x80eb
#define SVR_P2020 0x80e2
#define SVR_P2020E 0x80ea
+#define SVR_P4040 0x8200
+#define SVR_P4040E 0x8208
+#define SVR_P4080 0x8201
+#define SVR_P4080E 0x8209
#define SVR_VER(svr) (((svr) >> 16) & 0xffff)
#define SPR_PID0 0x030 /* ..8 Process ID Register 0 */
diff --git a/sys/powerpc/mpc85xx/mpc85xx.c b/sys/powerpc/mpc85xx/mpc85xx.c
index 564bf84..f383a1b 100644
--- a/sys/powerpc/mpc85xx/mpc85xx.c
+++ b/sys/powerpc/mpc85xx/mpc85xx.c
@@ -69,12 +69,13 @@ law_getmax(void)
uint32_t ver;
ver = SVR_VER(mfspr(SPR_SVR));
- if (ver == SVR_MPC8572E || ver == SVR_MPC8572)
- return (12);
- else if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
- return (10);
- else
+ if (ver == SVR_MPC8555E || ver == SVR_MPC8555)
return (8);
+ if (ver == SVR_MPC8548E || ver == SVR_MPC8548 ||
+ ver == SVR_MPC8533E || ver == SVR_MPC8533)
+ return (10);
+
+ return (12);
}
#define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | (ffsl(size) - 2))
@@ -152,10 +153,16 @@ law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
trgt = 1;
break;
case 0xa000:
- if (ver == SVR_MPC8572E || ver == SVR_MPC8572)
- trgt = 2;
+ if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
+ trgt = 3;
else
+ trgt = 2;
+ break;
+ case 0xb000:
+ if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
rv = EINVAL;
+ else
+ trgt = 3;
break;
default:
rv = ENXIO;
diff --git a/sys/powerpc/mpc85xx/mpc85xx.h b/sys/powerpc/mpc85xx/mpc85xx.h
index 7621f2c..fa3bde3 100644
--- a/sys/powerpc/mpc85xx/mpc85xx.h
+++ b/sys/powerpc/mpc85xx/mpc85xx.h
@@ -67,11 +67,6 @@
#define OCP85XX_PORDEVSR2 (CCSRBAR_VA + 0xe0014)
-#define OCP85XX_DEVDISR (CCSRBAR_VA + 0xe0070)
-#define OCP85XX_DEVDISR_PCIE0 0x20000000
-#define OCP85XX_DEVDISR_PCIE1 0x04000000
-#define OCP85XX_DEVDISR_PCIE2 0x02000000
-
/*
* Status Registers.
*/
diff --git a/sys/powerpc/powermac/powermac_thermal.c b/sys/powerpc/powermac/powermac_thermal.c
new file mode 100644
index 0000000..89637ca
--- /dev/null
+++ b/sys/powerpc/powermac/powermac_thermal.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2009-2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <sys/types.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+
+#include "powermac_thermal.h"
+
+static void fan_management_proc(void);
+static void pmac_therm_manage_fans(void);
+
+static struct proc *pmac_them_proc;
+static int enable_pmac_thermal = 1;
+
+static struct kproc_desc pmac_therm_kp = {
+ "pmac_thermal",
+ fan_management_proc,
+ &pmac_them_proc
+};
+
+SYSINIT(pmac_therm_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start,
+ &pmac_therm_kp);
+SYSCTL_INT(_machdep, OID_AUTO, manage_fans, CTLFLAG_RW | CTLFLAG_TUN,
+ &enable_pmac_thermal, 1, "Enable automatic fan management");
+MALLOC_DEFINE(M_PMACTHERM, "pmactherm", "Powermac Thermal Management");
+
+struct pmac_fan_le {
+ struct pmac_fan *fan;
+ int last_val;
+ SLIST_ENTRY(pmac_fan_le) entries;
+};
+struct pmac_sens_le {
+ struct pmac_therm *sensor;
+ int last_val;
+ SLIST_ENTRY(pmac_sens_le) entries;
+};
+static SLIST_HEAD(pmac_fans, pmac_fan_le) fans = SLIST_HEAD_INITIALIZER(fans);
+static SLIST_HEAD(pmac_sensors, pmac_sens_le) sensors =
+ SLIST_HEAD_INITIALIZER(sensors);
+
+static void
+fan_management_proc(void)
+{
+ /* Nothing to manage? */
+ if (SLIST_EMPTY(&fans))
+ return;
+
+ while (1) {
+ pmac_therm_manage_fans();
+ pause("pmac_therm", hz);
+ }
+}
+
+static void
+pmac_therm_manage_fans(void)
+{
+ struct pmac_sens_le *sensor;
+ struct pmac_fan_le *fan;
+ int average_excess, max_excess_zone, frac_excess;
+ int nsens, nsens_zone;
+
+ if (!enable_pmac_thermal)
+ return;
+
+ /* Read all the sensors */
+ SLIST_FOREACH(sensor, &sensors, entries) {
+ sensor->last_val = sensor->sensor->read(sensor->sensor);
+ if (sensor->last_val > sensor->sensor->max_temp) {
+ printf("WARNING: Current temperature (%s: %d.%d C) "
+ "exceeds critical temperature (%d.%d C)! "
+ "Shutting down!\n", sensor->sensor->name,
+ sensor->last_val / 10, sensor->last_val % 10,
+ sensor->sensor->max_temp / 10,
+ sensor->sensor->max_temp % 10);
+ shutdown_nice(RB_POWEROFF);
+ }
+ }
+
+ /* Set all the fans */
+ SLIST_FOREACH(fan, &fans, entries) {
+ nsens = nsens_zone = 0;
+ average_excess = max_excess_zone = 0;
+ SLIST_FOREACH(sensor, &sensors, entries) {
+ frac_excess = (sensor->last_val -
+ sensor->sensor->target_temp)*100 /
+ (sensor->sensor->max_temp -
+ sensor->sensor->target_temp);
+ if (sensor->sensor->zone == fan->fan->zone) {
+ max_excess_zone = imax(max_excess_zone,
+ frac_excess);
+ nsens_zone++;
+ }
+ average_excess += frac_excess;
+ nsens++;
+ }
+ average_excess /= nsens;
+
+ /* If there are no sensors in this zone, use the average */
+ if (nsens_zone == 0)
+ max_excess_zone = average_excess;
+ /* No sensors at all? Use default */
+ if (nsens == 0) {
+ fan->fan->set(fan->fan, fan->fan->default_rpm);
+ continue;
+ }
+
+ /*
+ * Scale the fan linearly in the max temperature in its
+ * thermal zone.
+ */
+ fan->fan->set(fan->fan, max_excess_zone *
+ (fan->fan->max_rpm - fan->fan->min_rpm)/100 +
+ fan->fan->min_rpm);
+ }
+}
+
+void
+pmac_thermal_fan_register(struct pmac_fan *fan)
+{
+ struct pmac_fan_le *list_entry;
+
+ list_entry = malloc(sizeof(struct pmac_fan_le), M_PMACTHERM,
+ M_ZERO | M_WAITOK);
+ list_entry->fan = fan;
+
+ SLIST_INSERT_HEAD(&fans, list_entry, entries);
+}
+
+void
+pmac_thermal_sensor_register(struct pmac_therm *sensor)
+{
+ struct pmac_sens_le *list_entry;
+
+ list_entry = malloc(sizeof(struct pmac_sens_le), M_PMACTHERM,
+ M_ZERO | M_WAITOK);
+ list_entry->sensor = sensor;
+
+ SLIST_INSERT_HEAD(&sensors, list_entry, entries);
+}
+
diff --git a/sys/powerpc/powermac/powermac_thermal.h b/sys/powerpc/powermac/powermac_thermal.h
new file mode 100644
index 0000000..43bd629
--- /dev/null
+++ b/sys/powerpc/powermac/powermac_thermal.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2009-2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _POWERPC_POWERMAC_POWERMAC_THERMAL_H
+#define _POWERPC_POWERMAC_POWERMAC_THERMAL_H
+
+struct pmac_fan {
+ int min_rpm, max_rpm, default_rpm;
+
+ char name[32];
+ int zone;
+
+ int (*read)(struct pmac_fan *);
+ int (*set)(struct pmac_fan *, int value);
+};
+
+struct pmac_therm {
+ int target_temp, max_temp; /* Tenths of a degree K */
+
+ char name[32];
+ int zone;
+
+ int (*read)(struct pmac_therm *);
+};
+
+void pmac_thermal_fan_register(struct pmac_fan *);
+void pmac_thermal_sensor_register(struct pmac_therm *);
+
+#endif
diff --git a/sys/powerpc/powermac/smu.c b/sys/powerpc/powermac/smu.c
index 928472c..09025b1 100644
--- a/sys/powerpc/powermac/smu.c
+++ b/sys/powerpc/powermac/smu.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <powerpc/powermac/macgpiovar.h>
+#include <powerpc/powermac/powermac_thermal.h>
#include "clock_if.h"
#include "iicbus_if.h"
@@ -69,19 +70,19 @@ struct smu_cmd {
STAILQ_HEAD(smu_cmdq, smu_cmd);
struct smu_fan {
+ struct pmac_fan fan;
+ device_t dev;
cell_t reg;
- cell_t min_rpm;
- cell_t max_rpm;
- cell_t unmanaged_rpm;
- char location[32];
int old_style;
int setpoint;
};
struct smu_sensor {
+ struct pmac_therm therm;
+ device_t dev;
+
cell_t reg;
- char location[32];
enum {
SMU_CURRENT_SENSOR,
SMU_VOLTAGE_SENSOR,
@@ -131,10 +132,6 @@ struct smu_softc {
uint16_t sc_slots_pow_scale;
int16_t sc_slots_pow_offset;
- /* Thermal management parameters */
- int sc_target_temp; /* Default 55 C */
- int sc_critical_temp; /* Default 90 C */
-
struct cdev *sc_leddev;
};
@@ -161,8 +158,6 @@ static int smu_get_datablock(device_t dev, int8_t id, uint8_t *buf,
static void smu_attach_i2c(device_t dev, phandle_t i2croot);
static void smu_attach_fans(device_t dev, phandle_t fanroot);
static void smu_attach_sensors(device_t dev, phandle_t sensroot);
-static void smu_fan_management_proc(void *xdev);
-static void smu_manage_fans(device_t smu);
static void smu_set_sleepled(void *xdev, int onoff);
static int smu_server_mode(SYSCTL_HANDLER_ARGS);
static void smu_doorbell_intr(void *xdev);
@@ -349,24 +344,6 @@ smu_attach(device_t dev)
sc->sc_slots_pow_offset = (data[6] << 8) + data[7];
/*
- * Set up simple-minded thermal management.
- */
- sc->sc_target_temp = 55;
- sc->sc_critical_temp = 90;
-
- SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "target_temp", CTLTYPE_INT | CTLFLAG_RW, &sc->sc_target_temp,
- sizeof(int), "Target temperature (C)");
- SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "critical_temp", CTLTYPE_INT | CTLFLAG_RW,
- &sc->sc_critical_temp, sizeof(int), "Critical temperature (C)");
-
- kproc_create(smu_fan_management_proc, dev, &sc->sc_fanmgt_proc,
- RFHIGHPID, 0, "smu_thermal");
-
- /*
* Set up LED interface
*/
sc->sc_leddev = led_create(smu_set_sleepled, dev, "sleepled");
@@ -658,8 +635,9 @@ doorbell_attach(device_t dev)
*/
static int
-smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
+smu_fan_set_rpm(struct smu_fan *fan, int rpm)
{
+ device_t smu = fan->dev;
struct smu_cmd cmd;
int error;
@@ -667,8 +645,8 @@ smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
error = EIO;
/* Clamp to allowed range */
- rpm = max(fan->min_rpm, rpm);
- rpm = min(fan->max_rpm, rpm);
+ rpm = max(fan->fan.min_rpm, rpm);
+ rpm = min(fan->fan.max_rpm, rpm);
/*
* Apple has two fan control mechanisms. We can't distinguish
@@ -684,7 +662,7 @@ smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
cmd.data[3] = rpm & 0xff;
error = smu_run_cmd(smu, &cmd, 1);
- if (error)
+ if (error && error != EWOULDBLOCK)
fan->old_style = 1;
}
@@ -704,8 +682,9 @@ smu_fan_set_rpm(device_t smu, struct smu_fan *fan, int rpm)
}
static int
-smu_fan_read_rpm(device_t smu, struct smu_fan *fan)
+smu_fan_read_rpm(struct smu_fan *fan)
{
+ device_t smu = fan->dev;
struct smu_cmd cmd;
int rpm, error;
@@ -716,7 +695,7 @@ smu_fan_read_rpm(device_t smu, struct smu_fan *fan)
cmd.data[1] = fan->reg;
error = smu_run_cmd(smu, &cmd, 1);
- if (error)
+ if (error && error != EWOULDBLOCK)
fan->old_style = 1;
rpm = (cmd.data[0] << 8) | cmd.data[1];
@@ -749,7 +728,7 @@ smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
sc = device_get_softc(smu);
fan = &sc->sc_fans[arg2];
- rpm = smu_fan_read_rpm(smu, fan);
+ rpm = smu_fan_read_rpm(fan);
if (rpm < 0)
return (rpm);
@@ -760,7 +739,7 @@ smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
sc->sc_lastuserchange = time_uptime;
- return (smu_fan_set_rpm(smu, fan, rpm));
+ return (smu_fan_set_rpm(fan, rpm));
}
static void
@@ -801,23 +780,25 @@ smu_attach_fans(device_t dev, phandle_t fanroot)
if (strcmp(type, "fan-rpm-control") != 0)
continue;
+ fan->dev = dev;
fan->old_style = 0;
OF_getprop(child, "reg", &fan->reg, sizeof(cell_t));
- OF_getprop(child, "min-value", &fan->min_rpm, sizeof(cell_t));
- OF_getprop(child, "max-value", &fan->max_rpm, sizeof(cell_t));
+ OF_getprop(child, "min-value", &fan->fan.min_rpm, sizeof(int));
+ OF_getprop(child, "max-value", &fan->fan.max_rpm, sizeof(int));
+ OF_getprop(child, "zone", &fan->fan.zone, sizeof(int));
- if (OF_getprop(child, "unmanaged-value", &fan->unmanaged_rpm,
- sizeof(cell_t)) != sizeof(cell_t))
- fan->unmanaged_rpm = fan->max_rpm;
+ if (OF_getprop(child, "unmanaged-value", &fan->fan.default_rpm,
+ sizeof(int)) != sizeof(int))
+ fan->fan.default_rpm = fan->fan.max_rpm;
- fan->setpoint = smu_fan_read_rpm(dev, fan);
+ fan->setpoint = smu_fan_read_rpm(fan);
- OF_getprop(child, "location", fan->location,
- sizeof(fan->location));
+ OF_getprop(child, "location", fan->fan.name,
+ sizeof(fan->fan.name));
/* Add sysctls */
- for (i = 0; i < strlen(fan->location); i++) {
- sysctl_name[i] = tolower(fan->location[i]);
+ for (i = 0; i < strlen(fan->fan.name); i++) {
+ sysctl_name[i] = tolower(fan->fan.name[i]);
if (isspace(sysctl_name[i]))
sysctl_name[i] = '_';
}
@@ -826,23 +807,28 @@ smu_attach_fans(device_t dev, phandle_t fanroot)
oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm",
- CTLTYPE_INT | CTLFLAG_RD, &fan->min_rpm, sizeof(cell_t),
+ CTLTYPE_INT | CTLFLAG_RD, &fan->fan.min_rpm, sizeof(int),
"Minimum allowed RPM");
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm",
- CTLTYPE_INT | CTLFLAG_RD, &fan->max_rpm, sizeof(cell_t),
+ CTLTYPE_INT | CTLFLAG_RD, &fan->fan.max_rpm, sizeof(int),
"Maximum allowed RPM");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm",
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev,
sc->sc_nfans, smu_fanrpm_sysctl, "I", "Fan RPM");
+ fan->fan.read = (int (*)(struct pmac_fan *))smu_fan_read_rpm;
+ fan->fan.set = (int (*)(struct pmac_fan *, int))smu_fan_set_rpm;
+ pmac_thermal_fan_register(&fan->fan);
+
fan++;
sc->sc_nfans++;
}
}
static int
-smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val)
+smu_sensor_read(struct smu_sensor *sens)
{
+ device_t smu = sens->dev;
struct smu_cmd cmd;
struct smu_softc *sc;
int64_t value;
@@ -855,7 +841,7 @@ smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val)
error = smu_run_cmd(smu, &cmd, 1);
if (error != 0)
- return (error);
+ return (-1);
sc = device_get_softc(smu);
value = (cmd.data[0] << 8) | cmd.data[1];
@@ -867,8 +853,8 @@ smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val)
value += ((int64_t)sc->sc_cpu_diode_offset) << 9;
value <<= 1;
- /* Convert from 16.16 fixed point degC into integer C. */
- value >>= 16;
+ /* Convert from 16.16 fixed point degC into integer 0.1 K. */
+ value = 10*(value >> 16) + 2732;
break;
case SMU_VOLTAGE_SENSOR:
value *= sc->sc_cpu_volt_scale;
@@ -902,8 +888,7 @@ smu_sensor_read(device_t smu, struct smu_sensor *sens, int *val)
break;
}
- *val = value;
- return (0);
+ return (value);
}
static int
@@ -918,9 +903,9 @@ smu_sensor_sysctl(SYSCTL_HANDLER_ARGS)
sc = device_get_softc(smu);
sens = &sc->sc_sensors[arg2];
- error = smu_sensor_read(smu, sens, &value);
- if (error != 0)
- return (error);
+ value = smu_sensor_read(sens);
+ if (value < 0)
+ return (EBUSY);
error = sysctl_handle_int(oidp, &value, 0, req);
@@ -964,6 +949,7 @@ smu_attach_sensors(device_t dev, phandle_t sensroot)
char sysctl_name[40], sysctl_desc[40];
const char *units;
+ sens->dev = dev;
OF_getprop(child, "device_type", type, sizeof(type));
if (strcmp(type, "current-sensor") == 0) {
@@ -983,98 +969,37 @@ smu_attach_sensors(device_t dev, phandle_t sensroot)
}
OF_getprop(child, "reg", &sens->reg, sizeof(cell_t));
- OF_getprop(child, "location", sens->location,
- sizeof(sens->location));
+ OF_getprop(child, "zone", &sens->therm.zone, sizeof(int));
+ OF_getprop(child, "location", sens->therm.name,
+ sizeof(sens->therm.name));
- for (i = 0; i < strlen(sens->location); i++) {
- sysctl_name[i] = tolower(sens->location[i]);
+ for (i = 0; i < strlen(sens->therm.name); i++) {
+ sysctl_name[i] = tolower(sens->therm.name[i]);
if (isspace(sysctl_name[i]))
sysctl_name[i] = '_';
}
sysctl_name[i] = 0;
- sprintf(sysctl_desc,"%s (%s)", sens->location, units);
+ sprintf(sysctl_desc,"%s (%s)", sens->therm.name, units);
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
- dev, sc->sc_nsensors, smu_sensor_sysctl, "I", sysctl_desc);
-
- sens++;
- sc->sc_nsensors++;
- }
-}
-
-static void
-smu_fan_management_proc(void *xdev)
-{
- device_t smu = xdev;
-
- while(1) {
- smu_manage_fans(smu);
- pause("smu", SMU_FANMGT_INTERVAL * hz / 1000);
- }
-}
-
-static void
-smu_manage_fans(device_t smu)
-{
- struct smu_softc *sc;
- int i, maxtemp, temp, factor, error;
-
- sc = device_get_softc(smu);
-
- maxtemp = 0;
- for (i = 0; i < sc->sc_nsensors; i++) {
- if (sc->sc_sensors[i].type != SMU_TEMP_SENSOR)
- continue;
-
- error = smu_sensor_read(smu, &sc->sc_sensors[i], &temp);
- if (error == 0 && temp > maxtemp)
- maxtemp = temp;
- }
+ dev, sc->sc_nsensors, smu_sensor_sysctl,
+ (sens->type == SMU_TEMP_SENSOR) ? "IK" : "I", sysctl_desc);
- if (maxtemp > sc->sc_critical_temp) {
- device_printf(smu, "WARNING: Current system temperature (%d C) "
- "exceeds critical temperature (%d C)! Shutting down!\n",
- maxtemp, sc->sc_critical_temp);
- shutdown_nice(RB_POWEROFF);
- }
-
- if (maxtemp - sc->sc_target_temp > 20)
- device_printf(smu, "WARNING: Current system temperature (%d C) "
- "more than 20 degrees over target temperature (%d C)!\n",
- maxtemp, sc->sc_target_temp);
-
- if (time_uptime - sc->sc_lastuserchange < 3) {
- /*
- * If we have heard from a user process in the last 3 seconds,
- * go away.
- */
+ if (sens->type == SMU_TEMP_SENSOR) {
+ /* Make up some numbers */
+ sens->therm.target_temp = 500 + 2732; /* 50 C */
+ sens->therm.max_temp = 900 + 2732; /* 90 C */
- return;
- }
+ sens->therm.read =
+ (int (*)(struct pmac_therm *))smu_sensor_read;
+ pmac_thermal_sensor_register(&sens->therm);
+ }
- if (maxtemp < 10) { /* Bail if no good sensors */
- for (i = 0; i < sc->sc_nfans; i++)
- smu_fan_set_rpm(smu, &sc->sc_fans[i],
- sc->sc_fans[i].unmanaged_rpm);
- return;
+ sens++;
+ sc->sc_nsensors++;
}
-
- if (maxtemp - sc->sc_target_temp > 4)
- factor = 110;
- else if (maxtemp - sc->sc_target_temp > 1)
- factor = 105;
- else if (sc->sc_target_temp - maxtemp > 4)
- factor = 90;
- else if (sc->sc_target_temp - maxtemp > 1)
- factor = 95;
- else
- factor = 100;
-
- for (i = 0; i < sc->sc_nfans; i++)
- smu_fan_set_rpm(smu, &sc->sc_fans[i],
- (sc->sc_fans[i].setpoint * factor) / 100);
}
static void
diff --git a/sys/powerpc/powermac/smusat.c b/sys/powerpc/powermac/smusat.c
index 42f023a..886cd4f 100644
--- a/sys/powerpc/powermac/smusat.c
+++ b/sys/powerpc/powermac/smusat.c
@@ -43,9 +43,13 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/openfirm.h>
+#include <powerpc/powermac/powermac_thermal.h>
+
struct smu_sensor {
+ struct pmac_therm therm;
+ device_t dev;
+
cell_t reg;
- char location[32];
enum {
SMU_CURRENT_SENSOR,
SMU_VOLTAGE_SENSOR,
@@ -57,6 +61,7 @@ struct smu_sensor {
static int smusat_probe(device_t);
static int smusat_attach(device_t);
static int smusat_sensor_sysctl(SYSCTL_HANDLER_ARGS);
+static int smusat_sensor_read(struct smu_sensor *sens);
MALLOC_DEFINE(M_SMUSAT, "smusat", "SMU Sattelite Sensors");
@@ -135,14 +140,16 @@ smusat_attach(device_t dev)
char sysctl_name[40], sysctl_desc[40];
const char *units;
+ sens->dev = dev;
sens->reg = 0;
OF_getprop(child, "reg", &sens->reg, sizeof(sens->reg));
if (sens->reg < 0x30)
continue;
-
sens->reg -= 0x30;
- OF_getprop(child, "location", sens->location,
- sizeof(sens->location));
+
+ OF_getprop(child, "zone", &sens->therm.zone, sizeof(int));
+ OF_getprop(child, "location", sens->therm.name,
+ sizeof(sens->therm.name));
OF_getprop(child, "device_type", type, sizeof(type));
@@ -162,17 +169,27 @@ smusat_attach(device_t dev)
continue;
}
- for (i = 0; i < strlen(sens->location); i++) {
- sysctl_name[i] = tolower(sens->location[i]);
+ for (i = 0; i < strlen(sens->therm.name); i++) {
+ sysctl_name[i] = tolower(sens->therm.name[i]);
if (isspace(sysctl_name[i]))
sysctl_name[i] = '_';
}
sysctl_name[i] = 0;
- sprintf(sysctl_desc,"%s (%s)", sens->location, units);
+ sprintf(sysctl_desc,"%s (%s)", sens->therm.name, units);
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
- sc->sc_nsensors, smusat_sensor_sysctl, "I", sysctl_desc);
+ sc->sc_nsensors, smusat_sensor_sysctl,
+ (sens->type == SMU_TEMP_SENSOR) ? "IK" : "I", sysctl_desc);
+
+ if (sens->type == SMU_TEMP_SENSOR) {
+ /* Make up some numbers */
+ sens->therm.target_temp = 500 + 2732; /* 50 C */
+ sens->therm.max_temp = 900 + 2732; /* 90 C */
+ sens->therm.read =
+ (int (*)(struct pmac_therm *))smusat_sensor_read;
+ pmac_thermal_sensor_register(&sens->therm);
+ }
sens++;
sc->sc_nsensors++;
@@ -198,11 +215,13 @@ smusat_updatecache(device_t dev)
}
static int
-smusat_sensor_read(device_t dev, struct smu_sensor *sens, int *val)
+smusat_sensor_read(struct smu_sensor *sens)
{
int value;
+ device_t dev;
struct smusat_softc *sc;
+ dev = sens->dev;
sc = device_get_softc(dev);
if (time_uptime - sc->sc_last_update > 1)
@@ -215,8 +234,8 @@ smusat_sensor_read(device_t dev, struct smu_sensor *sens, int *val)
case SMU_TEMP_SENSOR:
/* 16.16 */
value <<= 10;
- /* Kill the .16 */
- value >>= 16;
+ /* From 16.16 to 0.1 C */
+ value = 10*(value >> 16) + 2732;
break;
case SMU_VOLTAGE_SENSOR:
/* 16.16 */
@@ -235,8 +254,7 @@ smusat_sensor_read(device_t dev, struct smu_sensor *sens, int *val)
break;
}
- *val = value;
- return (0);
+ return (value);
}
static int
@@ -251,9 +269,9 @@ smusat_sensor_sysctl(SYSCTL_HANDLER_ARGS)
sc = device_get_softc(dev);
sens = &sc->sc_sensors[arg2];
- error = smusat_sensor_read(dev, sens, &value);
- if (error != 0)
- return (error);
+ value = smusat_sensor_read(sens);
+ if (value < 0)
+ return (EBUSY);
error = sysctl_handle_int(oidp, &value, 0, req);
OpenPOWER on IntegriCloud