Re: UltraSPARC III/IIe cpufreq drivers, please test

BERTRAND Joël <[email protected]>
Newsgroups gmane.os.netbsd.ports.sparc64
Message-ID <[email protected]>
	Hello,

	I'm adding a UltraSPARC-IIe cpufreq driver to psycho that runs on my 
Blade 100.

	Warning :
- I assume that an UltraSPARC-IIe system is ONLY and ALWAYS 
uniprocessor. I never see any US-IIe SMP system, but I'm not sure that 
all US-IIe systems are UP.
- I only has US-IIe, not US-IIi+ that could use /4 and /8 frequency 
dividers. Thus, I only use /1, /2 and /6, and I assume that regular 
US-IIe system run faster than 6*66 MHz (as cpu clock has to be greater 
than PCI clock).

	You will find a patch against 7.99.1 kernel. A prebuilt kernel is 
available at http://www.systella.fr/~bertrand/netbsd.gz

	Please test,

	JKB
cpufreq_patch2 (text/plain, 11.8 KB)
Index: dev/psycho.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/psycho.c,v
retrieving revision 1.118
diff -u -r1.118 psycho.c
--- dev/psycho.c	7 Dec 2013 11:17:24 -0000	1.118
+++ dev/psycho.c	13 Sep 2014 10:41:21 -0000
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 1999, 2000 Matthew R. Green
+ * Copyright (c) 2014 Joël Bertrand <[email protected]>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -85,6 +86,8 @@
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/reboot.h>
+#include <sys/cpu.h>
+#include <sys/cpufreq.h>
 
 #include <uvm/uvm.h>
 
@@ -124,6 +127,9 @@
 static int	psycho_pci_find_ino(const struct pci_attach_args *,
 				    pci_intr_handle_t *);
 
+void psycho_get_cpufreq(void *, void *);
+void psycho_set_cpufreq(void *, void *);
+
 /* Interrupt handlers */
 static int psycho_ue(void *);
 static int psycho_ce(void *);
@@ -276,6 +282,98 @@
 }
 #endif
 
+void
+psycho_set_cpufreq(void *aux, void *freq)
+{
+	uint32_t	f;
+
+	uint64_t	cmd;
+	uint64_t	esctrl;
+
+	struct psycho_softc *sc;
+
+	f = (*((uint32_t *) freq));
+	sc = curcpu()->sc;
+
+	if (sc == NULL)
+		return;
+
+	if (f == sc->sc_cf.cf_state[0].cfs_freq)
+		cmd = ESTAR_FULL;
+	else if (f == sc->sc_cf.cf_state[1].cfs_freq)
+		cmd = ESTAR_DIV_2;
+	else if (f == sc->sc_cf.cf_state[2].cfs_freq)
+		cmd = ESTAR_DIV_6;
+	else
+	{
+		aprint_error("cpufreq failed: switching to max frequency\n");
+		cmd = ESTAR_FULL;
+	}
+
+	esctrl = bus_space_read_8(sc->sc_bustag, sc->sc_bh,
+			offsetof(struct psychoreg, estar_mode));
+
+	esctrl &= (~0x111UL);
+	esctrl |= cmd;
+
+	bus_space_write_8(sc->sc_bustag, sc->sc_bh,
+		offsetof(struct psychoreg, estar_mode), esctrl);
+	aprint_normal("psycho_set_cpufreq %u MHz (cpu %lu)\n", f,
+			(unsigned long) cpu_number());
+}
+
+void
+psycho_get_cpufreq(void *aux, void *freq)
+{
+	uint32_t	f;
+	uint64_t	esctrl;
+
+	struct psycho_softc *sc;
+
+	sc = curcpu()->sc;
+
+	if (sc == NULL)
+		return;
+
+	esctrl = bus_space_read_8(sc->sc_bustag, sc->sc_bh,
+			offsetof(struct psychoreg, estar_mode));
+
+	switch(esctrl & (~0x111UL))
+	{
+		default:
+		case ESTAR_FULL:
+			f = sc->sc_cf.cf_state[0].cfs_freq;
+			break;
+
+		case ESTAR_DIV_2:
+			f = sc->sc_cf.cf_state[1].cfs_freq;
+			break;
+
+		case ESTAR_DIV_6:
+			f = sc->sc_cf.cf_state[2].cfs_freq;
+			break;
+	}
+
+	(*((uint32_t *) freq)) = f;
+	aprint_normal("psycho_get_cpufreq %u MHz (cpu %lu)\n", f,
+			(unsigned long) cpu_number());
+}
+
+static void
+psycho_setup_cpufreq(device_t dev)
+{
+	int	ret;
+	struct psycho_softc *sc = device_private(dev);
+
+	cpu_lookup(device_unit(dev))->sc = sc;
+	aprint_normal("register UltraSPARC-IIe cpufreq driver\n");
+	ret = cpufreq_register(&(sc->sc_cf));
+
+	if (ret != 0)
+		aprint_error_dev(sc->sc_dev, "failed to register cpufreq\n");
+}
+
+
 /*
  * SUNW,psycho initialisation ..
  *	- find the per-psycho registers
@@ -690,6 +788,27 @@
 	pba.pba_pc = pp->pp_pc;
 
 	config_found_ia(self, "pcibus", &pba, psycho_print);
+
+	if (strstr(cpu_getmodel(), "SUNW,UltraSPARC-IIe") != NULL)
+	{
+		(void) memset(&(sc->sc_cf), 0, sizeof(struct cpufreq));
+
+		sc->sc_cf.cf_state[0].cfs_freq =
+				(uint32_t) (curcpu()->ci_cpu_clockrate[1]);
+		sc->sc_cf.cf_state[1].cfs_freq = sc->sc_cf.cf_state[0].cfs_freq / 2;
+		sc->sc_cf.cf_state[2].cfs_freq = sc->sc_cf.cf_state[0].cfs_freq / 6;
+		sc->sc_cf.cf_state_count = 3;
+
+		sc->sc_cf.cf_mp = false;
+		sc->sc_cf.cf_cookie = NULL;
+		sc->sc_cf.cf_get_freq = psycho_get_cpufreq;
+		sc->sc_cf.cf_set_freq = psycho_set_cpufreq;
+
+		(void) strlcpy(sc->sc_cf.cf_name, "us2e cpufreq",
+				sizeof(sc->sc_cf.cf_name));
+
+		config_interrupts(sc->sc_dev, psycho_setup_cpufreq);
+	}
 }
 
 static	int
Index: dev/psychovar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/psychovar.h,v
retrieving revision 1.21
diff -u -r1.21 psychovar.h
--- dev/psychovar.h	7 Dec 2013 11:17:24 -0000	1.21
+++ dev/psychovar.h	13 Sep 2014 10:41:21 -0000
@@ -125,6 +125,7 @@
 	struct sysmon_pswitch		*sc_smcontext;	/* power switch definition */
 	int				sc_powerpressed;/* already signaled */
 	uint64_t			sc_last_stick;
+	struct cpufreq sc_cf;
 };
 
 /* get a PCI offset address from bus_space_handle_t */
Index: dev/schizo.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/schizo.c,v
retrieving revision 1.31
diff -u -r1.31 schizo.c
--- dev/schizo.c	21 Jun 2013 20:09:58 -0000	1.31
+++ dev/schizo.c	13 Sep 2014 10:41:21 -0000
@@ -5,6 +5,7 @@
  * Copyright (c) 2002 Jason L. Wright ([email protected])
  * Copyright (c) 2003 Henric Jungheim
  * Copyright (c) 2008, 2009, 2010, 2012 Matthew R. Green
+ * Copyright (c) 2014 Joël Bertrand ([email protected])
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,6 +42,8 @@
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/reboot.h>
+#include <sys/cpu.h>
+#include <sys/cpufreq.h>
 
 #define _SPARC_BUS_DMA_PRIVATE
 #include <sys/bus.h>
@@ -86,6 +89,9 @@
 int schizo_safari_error(void *);
 int schizo_pci_error(void *);
 
+void schizo_get_cpufreq(void *, void *);
+void schizo_set_cpufreq(void *, void *);
+
 pci_chipset_tag_t schizo_alloc_chipset(struct schizo_pbm *, int,
     pci_chipset_tag_t);
 bus_space_tag_t schizo_alloc_mem_tag(struct schizo_pbm *);
@@ -136,6 +142,100 @@
 }
 
 void
+schizo_set_cpufreq(void *aux, void *freq)
+{
+	uint32_t	f;
+
+	uint64_t	cmd;
+	uint64_t	esctrl;
+
+	struct schizo_softc *sc;
+
+	f = (*((uint32_t *) freq));
+	sc = curcpu()->sc;
+
+	if (sc == NULL)
+		return;
+
+	if (f == sc->sc_cf.cf_state[0].cfs_freq)
+		cmd = SCZ_ESCTRL_CLK_MAX;
+	else if (f == sc->sc_cf.cf_state[1].cfs_freq)
+		cmd = SCZ_ESCTRL_CLK_DIV_2;
+	else if (f == sc->sc_cf.cf_state[2].cfs_freq)
+		cmd = SCZ_ESCTRL_CLK_DIV_32;
+	else
+	{
+		aprint_error("cpufreq failed: switching to max frequency\n");
+		cmd = SCZ_ESCTRL_CLK_MAX;
+	}
+
+	esctrl = schizo_read(sc, SCZ_ESCTRL);
+	esctrl &= (~SCZ_ESCTRL_CLK_MASK);
+	esctrl |= cmd;
+	schizo_write(sc, SCZ_ESCTRL, esctrl);
+
+	aprint_normal("schizo_set_cpufreq %u MHz (cpu %lu)\n", f,
+			(unsigned long) cpu_number());
+}
+
+void
+schizo_get_cpufreq(void *aux, void *freq)
+{
+	uint32_t	f;
+	uint64_t	esctrl;
+
+	struct schizo_softc *sc;
+
+	sc = curcpu()->sc;
+
+	if (sc == NULL)
+		return;
+
+	esctrl = schizo_read(sc, SCZ_ESCTRL);
+
+	switch(esctrl & (~SCZ_ESCTRL_CLK_MASK))
+	{
+		default:
+		case SCZ_ESCTRL_CLK_MAX:
+			f = sc->sc_cf.cf_state[0].cfs_freq;
+			break;
+
+		case SCZ_ESCTRL_CLK_DIV_2:
+			f = sc->sc_cf.cf_state[1].cfs_freq;
+			break;
+
+		case SCZ_ESCTRL_CLK_DIV_32:
+			f = sc->sc_cf.cf_state[2].cfs_freq;
+			break;
+	}
+
+	(*((uint32_t *) freq)) = f;
+	aprint_normal("schizo_get_cpufreq %u MHz (cpu %lu)\n", f,
+			(unsigned long) cpu_number());
+}
+
+static void
+schizo_setup_cpufreq(device_t dev)
+{
+	// schizo_setup_cpufreq() is calling once by each schizo_attach().
+
+	struct schizo_softc *sc = device_private(dev);
+	int	ret;
+
+aprint_normal("device_unit(dev)=%d\n", device_unit(dev));	
+	cpu_lookup(device_unit(dev))->sc = sc;
+
+	if (device_unit(dev) == 0)
+	{
+		aprint_normal("register safari cpufreq driver\n");
+		ret = cpufreq_register(&(sc->sc_cf));
+
+		if (ret != 0)
+			aprint_error_dev(sc->sc_dev, "failed to register cpufreq\n");
+	}
+}
+
+void
 schizo_attach(device_t parent, device_t self, void *aux)
 {
 	struct schizo_softc *sc = device_private(self);
@@ -318,6 +418,26 @@
 	schizo_set_intr(sc, pbm, PIL_HIGH, schizo_safari_error, sc,
 	    SCZ_SERR_INO, "safari");
 
+	/*
+	 * Register with cpufreq(9)
+	 */
+
+	(void) memset(&(sc->sc_cf), 0, sizeof(struct cpufreq));
+
+	sc->sc_cf.cf_state[0].cfs_freq = (uint32_t) (curcpu()->ci_cpu_clockrate[1]);
+	sc->sc_cf.cf_state[1].cfs_freq = sc->sc_cf.cf_state[0].cfs_freq / 2;
+	sc->sc_cf.cf_state[2].cfs_freq = sc->sc_cf.cf_state[0].cfs_freq / 32;
+	sc->sc_cf.cf_state_count = 3;
+
+	sc->sc_cf.cf_mp = true;
+	sc->sc_cf.cf_cookie = NULL;
+	sc->sc_cf.cf_get_freq = schizo_get_cpufreq;
+	sc->sc_cf.cf_set_freq = schizo_set_cpufreq;
+
+	(void) strlcpy(sc->sc_cf.cf_name, "safari", sizeof(sc->sc_cf.cf_name));
+
+	config_interrupts(sc->sc_dev, schizo_setup_cpufreq);
+
 	if (sc->sc_tomatillo) {
 		/*
 		 * Enable the IOCACHE.
Index: dev/schizoreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/schizoreg.h,v
retrieving revision 1.9
diff -u -r1.9 schizoreg.h
--- dev/schizoreg.h	25 Mar 2012 03:13:08 -0000	1.9
+++ dev/schizoreg.h	13 Sep 2014 10:41:21 -0000
@@ -4,6 +4,7 @@
 /*
  * Copyright (c) 2002 Jason L. Wright ([email protected])
  * Copyright (c) 2010 Matthew R. Green
+ * Copyright (c) 2014 Joël Bertrand ([email protected])
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -15,7 +16,7 @@
  *    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 ``AS IS'' AND ANY EXPRESS OR
+ e THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 BE LIABLE FOR ANY DIRECT,
@@ -76,8 +77,9 @@
 	volatile u_int64_t	ue_afar;
 	volatile u_int64_t	ce_afsr;
 	volatile u_int64_t	ce_afar;
+	volatile u_int64_t	esctrl;
 
-	volatile u_int64_t	_unused4[253942];
+	volatile u_int64_t	_unused4[253941];
 	struct schizo_pbm_regs pbm_a;
 	struct schizo_pbm_regs pbm_b;
 };
@@ -101,6 +103,7 @@
 #define	SCZ_UE_AFAR			0x10038
 #define	SCZ_CE_AFSR			0x10040
 #define	SCZ_CE_AFAR			0x10048
+#define SCZ_ESCTRL			0x10050
 
 /* These are relative to the PBM */
 #define	SCZ_PCI_IOMMU_CTRL		0x00200
@@ -298,3 +301,8 @@
 	u_int32_t	size_hi;
 	u_int32_t	size_lo;
 };
+
+#define SCZ_ESCTRL_CLK_MAX		0x0000000000000000UL
+#define SCZ_ESCTRL_CLK_DIV_2	0x0000000040000000UL
+#define SCZ_ESCTRL_CLK_DIV_32	0x0000000080000000UL
+#define SCZ_ESCTRL_CLK_MASK		0x00000000C0000000UL
Index: dev/schizovar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/schizovar.h,v
retrieving revision 1.6
diff -u -r1.6 schizovar.h
--- dev/schizovar.h	25 Mar 2012 03:13:08 -0000	1.6
+++ dev/schizovar.h	13 Sep 2014 10:41:21 -0000
@@ -64,6 +64,7 @@
 	int sc_busa;
 	int sc_tomatillo;
 	uint32_t sc_ver;
+	struct cpufreq sc_cf;
 };
 
 #define	schizo_read(sc,r) \
Index: include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/include/cpu.h,v
retrieving revision 1.112
diff -u -r1.112 cpu.h
--- include/cpu.h	4 Sep 2014 18:48:29 -0000	1.112
+++ include/cpu.h	13 Sep 2014 10:41:22 -0000
@@ -199,6 +199,9 @@
 	bool			ci_pci_fault;
 
 	volatile void		*ci_ddb_regs;	/* DDB regs */
+
+	/* cpufreq */
+	void				*sc;
 };
 
 #endif /* _KERNEL || _KMEMUSER */
Index: sparc64/clock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/clock.c,v
retrieving revision 1.117
diff -u -r1.117 clock.c
--- sparc64/clock.c	25 Jul 2014 17:54:50 -0000	1.117
+++ sparc64/clock.c	13 Sep 2014 10:41:22 -0000
@@ -93,6 +93,7 @@
 #include "psycho.h"
 /* just because US-IIe STICK registers live in psycho space */
 #if NPSYCHO > 0
+#include <sys/cpufreq.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 #include <sparc64/dev/iommureg.h>
Index: sparc64/cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/cpu.c,v
retrieving revision 1.117
diff -u -r1.117 cpu.c
--- sparc64/cpu.c	1 Sep 2014 19:01:55 -0000	1.117
+++ sparc64/cpu.c	13 Sep 2014 10:41:22 -0000
@@ -362,6 +362,8 @@
 	}
 	aprint_normal_dev(dev, "");
 
+	ci->sc = NULL;
+
 	/* XXX sun4v mising cache info printout */
 	bigcache = 0;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.